Refactor calc non-linear ViewToDevice transform

This change solves the non-linear World-To-View trans-
formation that calc uses due to it's screen rendering
as good as currently possible (AFAIK).
Calcv view  is layouted on pixel base (due to better
homogen distances and full pixel lines between cells),
but this leads to having a non-linear transformation
between discrete units (pixels, view) and model coordinates
(World). In principle, each cell has it's own (so called)
ViewTransformation -> the position on screen depends on
the mappings of all cells top/left from it. This is
obvioulsly non-linear and can sometimes be seen by
producing 'offset' errors when many cells (small and thin)
are shown in low zoom stages.
No better solution for this comes to mind easily. The
extremes are - on the one hand AntiAliasing the whole
calc edit view and accept 'unsharp/AAed' lines - on the
other hand what we have now.
Maybe a future solution could find a mapping that gets
close to linear mapping for the full view. On the long
run this state is hard to keep correct. Even with this
extended solution the mapping of SdrObjects spawning
mutiple cells is assumed 'linear' in that area - which
is in reality currently not the case (!)
Note: This is only true for the screen visualization,
print and/or PDF export do not do that pixel-based
layouting.
Note2: This mechanism is general in DrawingLayer (look
for '.*GridOffset.*'. If it is deactivated by providing
no offsets, the result is the unchanged, linear mapping.

First step: Add interfaces to get a possible GridOffset
at ViewObjectContact. There it belongs, we have a view-
dependent offset per object and view. Add mechanisms to
create on-demand and reach back to the view (aka calc's
derivation of it).

Second step: Implement the on-demand creation, adapt to
use it in ViewObjectContact::getPrimitive2DSequence, add
stuff to reset on zoom change, disable temporarily old
mechanism -> paint already works. Need to adapt the
places from old mechanism where the GridOffset was used,
but no longer the geometry creations.

Third step: Isolated and disabled old mechanism (by
already removing SetGridOffset). Marked all places that
possibly need change with '//Z' tag. Main work now will
be to adapt in the SdrView implementations in svx to know
about having a SdrObject-dependent ViewTransformation
at all (currently not known, was hard-coded at some places
from the old code, ViewTransformation set as MapMode at
a target OutputDevice, not member at SdrView at all...).

Fourth step: Adapt the Handles and OverlayObjects to
use an evtl. existing GridOffset. The mechanism is that
the SdrHdl(s) can be seen as 'Model-Objects', these get
converted to OverlayObjects in the ::CreateB2dIAObject()
implementations, for all SdrMarkView and SdrPageView,
so this is the place where the ObjectContact is known
(the SdrPageWindow *is* a ObjectContact) and the view-
dependent GridOffset can be calculated per SdrObject.
I modified OverlayObject to be able to work with a
set Offset that embeds the created visualization using
this additionally.
Handles get now correctly set and have a working HitTest
(due to that already using the primitives). Some inter-
action stuff already working, some will need more
adaption. We simply have no concept for this stuff...
Refactored to not get dependencies to SdrObject in
ObjectContact.

Fifth Step: Make HitTest work by adding the View-And-
Object dependent GridOffset in the View when HitTest
is triggered. This is in SdrMarkView::CheckSingleSdrObjectHit
where pObj->GetCurrentBoundRect() is used that gets the
view-independent form. To make HitTest work, add a possible
GridOffset.
Since this will be necessary more often in SdrView hierarchy,
added a tooling method (getPossibleGridOffsetForSdrObject)
at that level after checking that at that level will be
reachable at all potential spots.
Inside that method the correct ObjectContact will be identified
and the object-specific offset requested there.

Sixth Step: Adaptions and started some cleanups. Still some
adaptions needed:
- After creation of new object, need to relocate from
  used GridOffset setting to WorldCoordinates
- Interactions, e.g. start with dragging handles or full
  object/points

Seventh Step: React on EndCreateObj. Here, the created
SdrObject is in model coordinates and needs to be adapted
to evtl. GridOffset. This is 'tricky' due to calculating
the possible offset based on new coordinates 'close'
to the target position, but may be in the wrong cell.
Nonetheless this is the best we can do here.
Last (hopefully) missing are now all interaction
viszualizations. They already work and are applied
correctly, but wrong visualized.
Have taken the time to unify adding OverlayObjects for
selection visualization to OverlayManager, see
handleNewOverlayObject. This does all needed when adding
OverlayObjects in one place where the GridOffset can
also be handled. It makles things more safe - not possible
to forget one of the three steps for others.

Eighth Step: Do the same unification for creating the
OverlayGeometry, also rename methods to make usage more
clear. We now have
  SdrHdl::insertNewlyCreatedOverlayObjectForSdrHdl
  SdrDragMethod::insertNewlyCreatedOverlayObjectForSdrDragMethod
which can do the needed GridOffset changes centralized.
Needed to get a ObjectContact for this at SdrDragMethod,
so adapted ::CreateOverlayGeometry implementations
accordingly. Missing is now the implementation in
insertNewlyCreatedOverlayObjectForSdrDragMethod to add
the GridOffset - if used. This has no SdrObject at this
time, so we will need a fallback to do the same using a
Range (Rectangle). The stuff doing this for SdrObject
already has a fallback and is based on using the Rectangle
from the SdrObject anyways, so this will be possible.

Ninth Step: Cleanup of old stuff (no more //Z), adapted
some usages of OverlayObject creations to use
getViewIndependentPrimitive2DContainer instead of the
view dependent parts so that offset applied to
drag-overlays is correct and not already added. Adapted
insertNewlyCreatedOverlayObjectForSdrDragMethod to use
calculateGridOffsetForB2DRange. Use now that instead of
SdrObject-based approach in calc - is more generic.
Getting closer, but still not complete - there is an
error with dragging the grepped handle somehow - the
offset for drag is somehow wrong.

Tenth Step: Corrected that offset error. Of course at
interaction start and progress (move) the coordinates
are in GrifOffset coordinates and need to be corrected
to Model coordinates. Done that at ::BegDragObj and
::MovDragObj, works well.
Of course there are exceptions for the crop-handles, so
needed to add setting the correct parameters at SdrHdl
when these got created, then all works as expected.

The strategy is to *not* change the model data itself
in any way, instead do all changes/adaptions in the
view-only code. This has minimal impact and is needed
due to having a 1:n relationship between model and
views anyways.
There are two directions: All visualizations are adapted
to take the GridOffset into account (SdrObjects, overlay,
handles, InteractionObjects, ...). In the other direction
input like MousePosition is in principle in calc EditView
in 'GridOffset'-coordinates and needs to be mapped back
before usage.

Change-Id: I2ecdd409def96a7248a26a65a22e59eb962880a0
Reviewed-on: https://gerrit.libreoffice.org/64057
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@cib.de>
diff --git a/chart2/source/controller/main/DragMethod_RotateDiagram.cxx b/chart2/source/controller/main/DragMethod_RotateDiagram.cxx
index 87415cd..88572d9 100644
--- a/chart2/source/controller/main/DragMethod_RotateDiagram.cxx
+++ b/chart2/source/controller/main/DragMethod_RotateDiagram.cxx
@@ -172,7 +172,9 @@

    return true;
}
void DragMethod_RotateDiagram::CreateOverlayGeometry(sdr::overlay::OverlayManager& rOverlayManager)
void DragMethod_RotateDiagram::CreateOverlayGeometry(
    sdr::overlay::OverlayManager& rOverlayManager,
    const sdr::contact::ObjectContact& rObjectContact)
{
    ::basegfx::B3DHomMatrix aCurrentTransform;
    aCurrentTransform.translate( -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0,
@@ -212,10 +214,14 @@
        // transform to 2D view coordinates
        aPolyPolygon.transform(rVCScene.getObjectTransformation());

        std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
            aPolyPolygon));
        rOverlayManager.add(*pNew);
        addToOverlayObjectList(std::move(pNew));
        std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(
            new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
                aPolyPolygon));

        insertNewlyCreatedOverlayObjectForSdrDragMethod(
            std::move(pNew),
            rObjectContact,
            rOverlayManager);
    }
}
} //namespace chart
diff --git a/chart2/source/controller/main/DragMethod_RotateDiagram.hxx b/chart2/source/controller/main/DragMethod_RotateDiagram.hxx
index 863e755..b2698bf 100644
--- a/chart2/source/controller/main/DragMethod_RotateDiagram.hxx
+++ b/chart2/source/controller/main/DragMethod_RotateDiagram.hxx
@@ -53,7 +53,9 @@
    virtual void MoveSdrDrag(const Point& rPnt) override;
    virtual bool EndSdrDrag(bool bCopy) override;

    virtual void CreateOverlayGeometry(sdr::overlay::OverlayManager& rOverlayManager) override;
    virtual void CreateOverlayGeometry(
        sdr::overlay::OverlayManager& rOverlayManager,
        const sdr::contact::ObjectContact& rObjectContact) override;

private:
    E3dScene*   m_pScene;
diff --git a/include/svx/sdr/contact/objectcontact.hxx b/include/svx/sdr/contact/objectcontact.hxx
index d305d61..dd1606e 100644
--- a/include/svx/sdr/contact/objectcontact.hxx
+++ b/include/svx/sdr/contact/objectcontact.hxx
@@ -163,6 +163,16 @@
    // wanted (like in such cases) this method is used. It will reuse the current
    // ViewInformation2D, but clear the ViewPort (no ViewPort means all is visible)
    void resetViewPort();

    // interface to support GridOffset for non-linear ViewToDevice transformation (calc)
    virtual bool supportsGridOffsets() const;
    virtual void calculateGridOffsetForViewOjectContact(
        basegfx::B2DVector& rTarget,
        const ViewObjectContact& rClient) const;
    virtual void calculateGridOffsetForB2DRange(
        basegfx::B2DVector& rTarget,
        const basegfx::B2DRange& rB2DRange) const;
    void resetAllGridOffsets();
};

}}
diff --git a/svx/inc/sdr/contact/objectcontactofpageview.hxx b/include/svx/sdr/contact/objectcontactofpageview.hxx
similarity index 97%
rename from svx/inc/sdr/contact/objectcontactofpageview.hxx
rename to include/svx/sdr/contact/objectcontactofpageview.hxx
index 4fb0bef..020b454 100644
--- a/svx/inc/sdr/contact/objectcontactofpageview.hxx
+++ b/include/svx/sdr/contact/objectcontactofpageview.hxx
@@ -30,7 +30,7 @@
{
    namespace contact
    {
        class ObjectContactOfPageView final : public ObjectContact, public Idle
        class SVX_DLLPUBLIC ObjectContactOfPageView : public ObjectContact, public Idle
        {
            // the owner of this ObjectContactOfPageView. Set from constructor and not
            // to be changed in any way.
diff --git a/include/svx/sdr/contact/viewobjectcontact.hxx b/include/svx/sdr/contact/viewobjectcontact.hxx
index ce17890..a6d929c 100644
--- a/include/svx/sdr/contact/viewobjectcontact.hxx
+++ b/include/svx/sdr/contact/viewobjectcontact.hxx
@@ -58,6 +58,9 @@
    // the PrimitiveAnimation if Primitive2DContainer contains animations
    std::unique_ptr<sdr::animation::PrimitiveAnimation> mpPrimitiveAnimation;

    // possible on-demand calculated GridOffset for non-linear ViewToDevice transformation (calc)
    basegfx::B2DVector                              maGridOffset;

    // This bool gets set when the object gets invalidated by ActionChanged() and
    // can be used from the OC to late-invalidates
    bool                                            mbLazyInvalidate : 1;
@@ -124,6 +127,10 @@

    // just process the sub-hierarchy, used as tooling from getPrimitive2DSequenceHierarchy
    drawinglayer::primitive2d::Primitive2DContainer getPrimitive2DSequenceSubHierarchy(DisplayInfo& rDisplayInfo) const;

    // interface to support GridOffset for non-linear ViewToDevice transformation (calc)
    const basegfx::B2DVector& getGridOffset() const;
    void resetGridOffset();
};

}}
diff --git a/include/svx/sdr/overlay/overlayobject.hxx b/include/svx/sdr/overlay/overlayobject.hxx
index a506d33..1470819 100644
--- a/include/svx/sdr/overlay/overlayobject.hxx
+++ b/include/svx/sdr/overlay/overlayobject.hxx
@@ -65,14 +65,25 @@
            OverlayManager*                                 mpOverlayManager;

            // Primitive2DContainer of the OverlayObject
            drawinglayer::primitive2d::Primitive2DContainer  maPrimitive2DSequence;
            drawinglayer::primitive2d::Primitive2DContainer maPrimitive2DSequence;

            // Possible Offset added to the geometry (automatically in
            // createOverlayObjectPrimitive2DSequence()). Usually zero, may
            // be used e.g. from calc when GridOffset is needed
            basegfx::B2DVector                              maOffset;

        protected:
            // access methods to maPrimitive2DSequence. The usage of this methods may allow
            // later thread-safe stuff to be added if needed. Only to be used by getPrimitive2DSequence()
            // implementations for buffering the last decomposition.
            // Resetting is allowed e.g. in ::getOverlayObjectPrimitive2DSequence() implementations
            // if the conditions have changed to force a re-creation in calling the base implementation.
            // The only allowed setter of maPrimitive2DSequence is
            // OverlayObject::getOverlayObjectPrimitive2DSequence() which should be called by calling
            // the base implementation in derived functions. That one will use the result of
            // createOverlayObjectPrimitive2DSequence() to provide the geometry.
            const drawinglayer::primitive2d::Primitive2DContainer& getPrimitive2DSequence() const { return maPrimitive2DSequence; }
            void setPrimitive2DSequence(const drawinglayer::primitive2d::Primitive2DContainer& rNew) { maPrimitive2DSequence = rNew; }
            void resetPrimitive2DSequence() { maPrimitive2DSequence.clear(); }

            // the creation method for Primitive2DContainer. Called when getPrimitive2DSequence()
            // sees that maPrimitive2DSequence is empty. Needs to be supported by all
@@ -146,6 +157,10 @@
            const Color& getBaseColor() const { return maBaseColor; }
            void setBaseColor(Color aNew);

            // access to Offset
            const basegfx::B2DVector& getOffset() const { return maOffset; }
            void setOffset(const basegfx::B2DVector& rOffset);

            // execute event from base class sdr::animation::Event. Default
            // implementation does nothing and does not create a new event.
            virtual void Trigger(sal_uInt32 nTime) override;
diff --git a/include/svx/svddrgmt.hxx b/include/svx/svddrgmt.hxx
index 0013da3..3e1a13d 100644
--- a/include/svx/svddrgmt.hxx
+++ b/include/svx/svddrgmt.hxx
@@ -66,11 +66,12 @@
private:
    const SdrObject&                                maOriginal;
    SdrObject*                                      mpClone;
    sdr::contact::ObjectContact&                    mrObjectContact;
    bool const                                      mbModify;

public:
    SdrDragEntrySdrObject(const SdrObject& rOriginal, sdr::contact::ObjectContact& rObjectContact, bool bModify);
    SdrDragEntrySdrObject(
        const SdrObject& rOriginal,
        bool bModify);
    virtual ~SdrDragEntrySdrObject() override;

    // #i54102# Split createPrimitive2DSequenceInCurrentState in prepareCurrentState and processing,
@@ -127,10 +128,19 @@
    void clearSdrDragEntries();
    void addSdrDragEntry(std::unique_ptr<SdrDragEntry> pNew);
    virtual void createSdrDragEntries();
    virtual void createSdrDragEntryForSdrObject(const SdrObject& rOriginal, sdr::contact::ObjectContact& rObjectContact);
    virtual void createSdrDragEntryForSdrObject(const SdrObject& rOriginal);

    // access for derivated classes to maOverlayObjectList (passes ownership)
    void addToOverlayObjectList(std::unique_ptr<sdr::overlay::OverlayObject> pNew) { maOverlayObjectList.append(std::move(pNew)); }
    // Helper to support inserting a new OverlayObject. It will do all
    // necessary stuff involved with that:
    // - add GridOffset for non-linear ViewToDevice transformation (calc)
    // - add to OverlayManager
    // - add to local OverlayObjectList - ownership change (!)
    // It is centralized here (and protected) to avoid that new usages/
    // implementations forget one of these needed steps.
    void insertNewlyCreatedOverlayObjectForSdrDragMethod(
        std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject,
        const sdr::contact::ObjectContact& rObjectContact,
        sdr::overlay::OverlayManager& rOverlayManager);

    // access for derivated classes to mrSdrDragView
    SdrDragView& getSdrDragView() { return mrSdrDragView; }
@@ -192,7 +202,9 @@
    virtual void CancelSdrDrag();
    virtual Pointer GetSdrDragPointer() const=0;

    virtual void CreateOverlayGeometry(sdr::overlay::OverlayManager& rOverlayManager);
    virtual void CreateOverlayGeometry(
        sdr::overlay::OverlayManager& rOverlayManager,
        const sdr::contact::ObjectContact& rObjectContact);
    void destroyOverlayGeometry();

    virtual basegfx::B2DHomMatrix getCurrentTransformation();
@@ -225,7 +237,7 @@
    void ImpCheckSnap(const Point& rPt);

protected:
    virtual void createSdrDragEntryForSdrObject(const SdrObject& rOriginal, sdr::contact::ObjectContact& rObjectContact) override;
    virtual void createSdrDragEntryForSdrObject(const SdrObject& rOriginal) override;

public:
    SdrDragMove(SdrDragView& rNewView);
diff --git a/include/svx/svdhdl.hxx b/include/svx/svdhdl.hxx
index 5760d64..caf9581 100644
--- a/include/svx/svdhdl.hxx
+++ b/include/svx/svdhdl.hxx
@@ -41,6 +41,10 @@
class SdrPageView;
class MouseEvent;

namespace sdr { namespace contact {
    class ObjectContact;
}}

// Every object must be able to create its handles. They will be fetched on
// selection, registered at the View and made visible.
// When a handle is touched by the mouse (IsHit()), from the view the matching mouse pointer
@@ -171,6 +175,18 @@
        Point aMoveOutsideOffset = Point());
    static BitmapMarkerKind GetNextBigger(BitmapMarkerKind eKnd);

    // Helper to support inserting a new OverlayObject. It will do all
    // necessary stuff involved with that:
    // - add GridOffset for non-linear ViewToDevice transformation (calc)
    // - add to OverlayManager
    // - add to local OverlayObjectList - ownership change (!)
    // It is centralized here (and protected) to avoid that new usages/
    // implementations forget one of these needed steps.
    void insertNewlyCreatedOverlayObjectForSdrHdl(
        std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject,
        const sdr::contact::ObjectContact& rObjectContact,
        sdr::overlay::OverlayManager& rOverlayManager);

public:
    SdrHdl();
    explicit SdrHdl(const Point& rPnt, SdrHdlKind eNewKind);
diff --git a/include/svx/svdmrkv.hxx b/include/svx/svdmrkv.hxx
index fd9d239..83eefb9 100644
--- a/include/svx/svdmrkv.hxx
+++ b/include/svx/svdmrkv.hxx
@@ -105,7 +105,6 @@
    sdr::ViewSelection          maSdrViewSelection;

    tools::Rectangle            maMarkedObjRect;
    tools::Rectangle            maMarkedObjRectNoOffset;
    tools::Rectangle            maMarkedPointsRect;
    tools::Rectangle            maMarkedGluePointsRect;

@@ -126,6 +125,18 @@
    // flag to completely disable handles at the view
    bool                        mbMarkHandlesHidden : 1;

    // Helper to get a possible GridOffset from SdrObject
    bool getPossibleGridOffsetForSdrObject(
        basegfx::B2DVector& rOffset,
        const SdrObject* pObj,
        const SdrPageView* pPV) const;

    // Helper to get a possible GridOffset from Position
    bool getPossibleGridOffsetForPosition(
        basegfx::B2DVector& rOffset,
        const basegfx::B2DPoint& rPoint,
        const SdrPageView* pPV) const;

private:
    SVX_DLLPRIVATE void ImpClearVars();
    SVX_DLLPRIVATE void ImpSetPointsRects() const;
@@ -398,7 +409,6 @@
    const tools::Rectangle& GetMarkedGluePointsRect() const; // Enclosing rectangle of all marked glue points
    const tools::Rectangle& GetAllMarkedRect() const { return GetMarkedObjRect(); }
    tools::Rectangle GetAllMarkedBoundRect() const { return GetMarkedObjBoundRect(); }
    Point GetGridOffset() const;

    // Will be always called, if the list of marked objects might be changed.
    // If you override this method, be sure that you call the
diff --git a/include/svx/svdobj.hxx b/include/svx/svdobj.hxx
index 2a1507ac..db1f4d1 100644
--- a/include/svx/svdobj.hxx
+++ b/include/svx/svdobj.hxx
@@ -382,9 +382,6 @@
    sal_Int16 GetRelativeWidthRelation() const;
    const double* GetRelativeHeight() const;
    sal_Int16 GetRelativeHeightRelation() const;
    // evil calc grid/shape drawlayer syncing
    const Point& GetGridOffset() const { return aGridOffset; }
    void SetGridOffset( const Point& rGridOffset ){ aGridOffset = rGridOffset; }

    /// @param bNotMyself = true: set only ObjList to dirty, don't mark this object as dirty.
    ///
@@ -998,7 +995,6 @@
private:
    struct Impl;
    std::unique_ptr<Impl>             mpImpl;
    Point                             aGridOffset;  // hack (Calc)
    SdrObjList*                       mpParentOfSdrObject;     // list that includes this object
    sal_uInt32                        nOrdNum;      // order number of the object in the list
    std::unique_ptr<SfxGrabBagItem>   pGrabBagItem; // holds the GrabBagItem property
diff --git a/include/svx/svdview.hxx b/include/svx/svdview.hxx
index a470891..677ba9b 100644
--- a/include/svx/svdview.hxx
+++ b/include/svx/svdview.hxx
@@ -50,6 +50,7 @@
//         SdrView         View

class SvxURLField;
namespace sdr { namespace contact { class ObjectContact; }}

enum class SdrViewContext {
    Standard,
@@ -234,6 +235,12 @@
    SvtAccessibilityOptions& getAccessibilityOptions() { return maAccessibilityOptions;}

    virtual void onAccessibilityOptionsChanged();

    // Do not create ObjectContact locally, but offer a call to allow override
    // and to create own derivations of ObjectContact
    virtual sdr::contact::ObjectContact* createViewSpecificObjectContact(
        SdrPageWindow& rPageWindow,
        const sal_Char* pDebugName) const;
};

// First of all the app creates a SdrModel.
diff --git a/sc/inc/drwlayer.hxx b/sc/inc/drwlayer.hxx
index 738ee08..143868c 100644
--- a/sc/inc/drwlayer.hxx
+++ b/sc/inc/drwlayer.hxx
@@ -176,8 +176,15 @@
    static void             SetPageAnchored( SdrObject& );
    static void             SetCellAnchored( SdrObject&, const ScDrawObjData &rAnchor );
    static void             SetVisualCellAnchored( SdrObject&, const ScDrawObjData &rAnchor );

    // Updates rAnchor based on position of rObj
    static void             GetCellAnchorFromPosition( const SdrObject &rObj, ScDrawObjData &rAnchor, const ScDocument &rDoc, SCTAB nTab, bool bUseLogicRect = true, bool bHiddenAsZero = true );
    static void GetCellAnchorFromPosition(
        const tools::Rectangle &rRectangle,
        ScDrawObjData &rAnchor,
        const ScDocument &rDoc,
        SCTAB nTab,
        bool bHiddenAsZero = true);

    static void             SetCellAnchoredFromPosition( SdrObject &rObj, const ScDocument &rDoc, SCTAB nTab, bool bResizeWithCell );
    static void             UpdateCellAnchorFromPositionEnd( const SdrObject &rObj, ScDrawObjData &rAnchor, const ScDocument &rDoc, SCTAB nTab, bool bUseLogicRect = true );
    static ScAnchorType     GetAnchorType( const SdrObject& );
diff --git a/sc/source/core/data/drwlayer.cxx b/sc/source/core/data/drwlayer.cxx
index 540e320..d7dc576 100644
--- a/sc/source/core/data/drwlayer.cxx
+++ b/sc/source/core/data/drwlayer.cxx
@@ -995,7 +995,14 @@
            // Ok, here is more nastiness, from xml the Anchor is in terms of the LogicRect which is the
            // untransformed unrotated shape, here we swap out that initial anchor and from now on use
            // an Anchor based on the SnapRect ( which is what you see on the screen )
            ScDrawLayer::GetCellAnchorFromPosition( *pObj, rData, *pDoc, nTab1, false, false );
            const tools::Rectangle aObjRect(pObj->GetSnapRect());
            ScDrawLayer::GetCellAnchorFromPosition(
                aObjRect,
                rData,
                *pDoc,
                nTab1,
                false);

            // reset shape to true 'maybe affected by hidden rows/cols' size calculated previously
            pObj->SetLogicRect(rNoRotatedAnchor.getShapeRect());
        }
@@ -2015,13 +2022,25 @@
    ScDrawObjData aAnchor;
    // set anchor in terms of the visual ( SnapRect )
    // object ( e.g. for when object is rotated )
    GetCellAnchorFromPosition( rObj, aAnchor, rDoc, nTab, false );
    const tools::Rectangle aObjRect(rObj.GetSnapRect());
    GetCellAnchorFromPosition(
        aObjRect,
        aAnchor,
        rDoc,
        nTab);

    aAnchor.mbResizeWithCell = bResizeWithCell;
    SetCellAnchored( rObj, aAnchor );
    // - keep also an anchor in terms of the Logic ( untransformed ) object
    // because that's what we stored ( and still do ) to xml
    ScDrawObjData aVisAnchor;
    GetCellAnchorFromPosition( rObj, aVisAnchor, rDoc, nTab );
    const tools::Rectangle aObjRect2(rObj.GetLogicRect());
    GetCellAnchorFromPosition(
        aObjRect2,
        aVisAnchor,
        rDoc,
        nTab);

    aVisAnchor.mbResizeWithCell = bResizeWithCell;
    SetVisualCellAnchored( rObj, aVisAnchor );
    // absolutely necessary to set flag that in order to prevent ScDrawLayer::RecalcPos
@@ -2032,31 +2051,34 @@
    }
}

void ScDrawLayer::GetCellAnchorFromPosition( const SdrObject &rObj, ScDrawObjData &rAnchor, const ScDocument &rDoc, SCTAB nTab, bool bUseLogicRect, bool bHiddenAsZero )
void ScDrawLayer::GetCellAnchorFromPosition(
    const tools::Rectangle &rObjRect,
    ScDrawObjData &rAnchor,
    const ScDocument &rDoc,
    SCTAB nTab,
    bool bHiddenAsZero)
{
    tools::Rectangle aObjRect( bUseLogicRect ? rObj.GetLogicRect() : rObj.GetSnapRect() );
    ScRange aRange = rDoc.GetRange( nTab, aObjRect, bHiddenAsZero );
    ScRange aRange = rDoc.GetRange( nTab, rObjRect, bHiddenAsZero );

    tools::Rectangle aCellRect;

    rAnchor.maStart = aRange.aStart;
    aCellRect = rDoc.GetMMRect( aRange.aStart.Col(), aRange.aStart.Row(),
      aRange.aStart.Col(), aRange.aStart.Row(), aRange.aStart.Tab(), bHiddenAsZero );
    rAnchor.maStartOffset.setY( aObjRect.Top()-aCellRect.Top() );
    rAnchor.maStartOffset.setY( rObjRect.Top()-aCellRect.Top() );
    if (!rDoc.IsNegativePage(nTab))
        rAnchor.maStartOffset.setX( aObjRect.Left()-aCellRect.Left() );
        rAnchor.maStartOffset.setX( rObjRect.Left()-aCellRect.Left() );
    else
        rAnchor.maStartOffset.setX( aCellRect.Right()-aObjRect.Right() );
        rAnchor.maStartOffset.setX( aCellRect.Right()-rObjRect.Right() );

    rAnchor.maEnd = aRange.aEnd;
    aCellRect = rDoc.GetMMRect( aRange.aEnd.Col(), aRange.aEnd.Row(),
      aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aEnd.Tab(), bHiddenAsZero );
    rAnchor.maEndOffset.setY( aObjRect.Bottom()-aCellRect.Top() );
    rAnchor.maEndOffset.setY( rObjRect.Bottom()-aCellRect.Top() );
    if (!rDoc.IsNegativePage(nTab))
        rAnchor.maEndOffset.setX( aObjRect.Right()-aCellRect.Left() );
        rAnchor.maEndOffset.setX( rObjRect.Right()-aCellRect.Left() );
    else
        rAnchor.maEndOffset.setX( aCellRect.Right()-aObjRect.Left() );

        rAnchor.maEndOffset.setX( aCellRect.Right()-rObjRect.Left() );
}

void ScDrawLayer::UpdateCellAnchorFromPositionEnd( const SdrObject &rObj, ScDrawObjData &rAnchor, const ScDocument &rDoc, SCTAB nTab, bool bUseLogicRect )
diff --git a/sc/source/ui/drawfunc/fuconarc.cxx b/sc/source/ui/drawfunc/fuconarc.cxx
index 6d22c74..8fde47d 100644
--- a/sc/source/ui/drawfunc/fuconarc.cxx
+++ b/sc/source/ui/drawfunc/fuconarc.cxx
@@ -46,14 +46,8 @@
    if ( rMEvt.IsLeft() && !pView->IsAction() )
    {
        Point aPnt( pWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
        // Hack  to align object to nearest grid position where object
        // would be anchored ( if it were cell anchored )
        // Get grid offset for current position ( note: aPnt is
        // also adjusted )
        Point aGridOff = CurrentGridSyncOffsetAndPos( aPnt );
        pWindow->CaptureMouse();
        pView->BegCreateObj( aPnt );
        pView->GetCreateObj()->SetGridOffset( aGridOff );
        bReturn = true;
    }
    return bReturn;
diff --git a/sc/source/ui/drawfunc/fuconcustomshape.cxx b/sc/source/ui/drawfunc/fuconcustomshape.cxx
index c2169a1..23eebb2 100644
--- a/sc/source/ui/drawfunc/fuconcustomshape.cxx
+++ b/sc/source/ui/drawfunc/fuconcustomshape.cxx
@@ -61,12 +61,6 @@
    if ( rMEvt.IsLeft() && !pView->IsAction() )
    {
        Point aPnt( pWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
        // Hack  to align object to nearest grid position where object
        // would be anchored ( if it were cell anchored )
        // Get grid offset for current position ( note: aPnt is
        // also adjusted )
        Point aGridOff = CurrentGridSyncOffsetAndPos( aPnt );

        pWindow->CaptureMouse();
        pView->BegCreateObj(aPnt);

@@ -79,7 +73,6 @@
                bForceNoFillStyle = true;
            if ( bForceNoFillStyle )
                pObj->SetMergedItem( XFillStyleItem( drawing::FillStyle_NONE ) );
            pObj->SetGridOffset( aGridOff );
        }

        bReturn = true;
diff --git a/sc/source/ui/drawfunc/fuconrec.cxx b/sc/source/ui/drawfunc/fuconrec.cxx
index d87a2b4..a77bda2 100644
--- a/sc/source/ui/drawfunc/fuconrec.cxx
+++ b/sc/source/ui/drawfunc/fuconrec.cxx
@@ -92,11 +92,6 @@
    if ( rMEvt.IsLeft() && !pView->IsAction() )
    {
        Point aPos( pWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
        // Hack  to align object to nearest grid position where object
        // would be anchored ( if it were cell anchored )
        // Get grid offset for current position ( note: aPnt is
        // also adjusted )
        Point aGridOff = CurrentGridSyncOffsetAndPos( aPos );
        pWindow->CaptureMouse();

        if ( pView->GetCurrentObjIdentifier() == OBJ_CAPTION )
@@ -118,9 +113,6 @@
            SetLineEnds(aAttr, *pObj, aSfxRequest.GetSlot());
            pObj->SetMergedItemSet(aAttr);
        }

        if ( bReturn )
            pView->GetCreateObj()->SetGridOffset( aGridOff );
    }
    return bReturn;
}
diff --git a/sc/source/ui/drawfunc/fuconstr.cxx b/sc/source/ui/drawfunc/fuconstr.cxx
index df5bb72..e6f61bd 100644
--- a/sc/source/ui/drawfunc/fuconstr.cxx
+++ b/sc/source/ui/drawfunc/fuconstr.cxx
@@ -46,47 +46,6 @@
{
}

// Calculate and return offset at current zoom. rInOutPos is adjusted by
// the calculated offset. rInOutPos now points to the position than when
// scaled to 100% actually would be at the position you see at the current zoom
// ( relative to the grid ) note: units are expected to be in 100th mm
Point FuConstruct::CurrentGridSyncOffsetAndPos( Point& rInOutPos )
{
    Point aRetGridOff;
    ScViewData& rViewData = rViewShell.GetViewData();
    ScDocument* pDoc = rViewData.GetDocument();
    if ( pDoc )
    {
        // rInOutPos might not be where you think it is if there is zoom
        // involved. Lets calculate where aPos would be at 100% zoom
        // that's the actual correct position for the object (when you
        // restore the zoom.
        bool bNegative = pDoc->IsNegativePage(pView->GetTab());
        tools::Rectangle aObjRect( rInOutPos, rInOutPos );
        ScRange aRange = pDoc->GetRange( pView->GetTab(), aObjRect );
        ScAddress aOldStt = aRange.aStart;
        Point aOldPos( pDoc->GetColOffset( aOldStt.Col(), aOldStt.Tab()  ), pDoc->GetRowOffset( aOldStt.Row(), aOldStt.Tab() ) );
        aOldPos.setX( sc::TwipsToHMM( aOldPos.X() ) );
        aOldPos.setY( sc::TwipsToHMM( aOldPos.Y() ) );
        ScSplitPos eWhich = rViewData.GetActivePart();
        ScGridWindow* pGridWin = rViewData.GetActiveWin();
        // and equiv screen pos
        Point aScreenPos =  rViewShell.GetViewData().GetScrPos( aOldStt.Col(), aOldStt.Row(), eWhich, true );
        MapMode aDrawMode = pGridWin->GetDrawMapMode();
        Point aCurPosHmm = pGridWin->PixelToLogic(aScreenPos, aDrawMode );
        Point aOff = ( rInOutPos - aCurPosHmm );
        rInOutPos = aOldPos + aOff;
        aRetGridOff = aCurPosHmm - aOldPos;
        // fdo#64011 fix the X position when the sheet are RTL
        if ( bNegative )
        {
            aRetGridOff.setX( aCurPosHmm.getX() + aOldPos.getX() );
            rInOutPos.setX( aOff.getX() - aOldPos.getX() );
        }
    }
    return aRetGridOff;
}

bool FuConstruct::MouseButtonDown(const MouseEvent& rMEvt)
{
    // remember button state for creation of own MouseEvents
@@ -144,12 +103,6 @@
    Point aPix(rMEvt.GetPosPixel());
    Point aPnt( pWindow->PixelToLogic(aPix) );

    // if object is being created then more than likely the mouse
    // position has been 'adjusted' for the current zoom, need to
    // restore the mouse position here to ensure resize works as expected
    if ( pView->GetCreateObj() )
        aPnt -= pView->GetCreateObj()->GetGridOffset();

    if ( pView->IsAction() )
    {
        ForceScroll(aPix);
diff --git a/sc/source/ui/drawfunc/fuconuno.cxx b/sc/source/ui/drawfunc/fuconuno.cxx
index ba0c0b5..3fe103a 100644
--- a/sc/source/ui/drawfunc/fuconuno.cxx
+++ b/sc/source/ui/drawfunc/fuconuno.cxx
@@ -50,15 +50,8 @@
    if ( rMEvt.IsLeft() && !pView->IsAction() )
    {
        Point aPnt( pWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
        // Hack  to align object to nearest grid position where object
        // would be anchored ( if it were cell anchored )
        // Get grid offset for current position ( note: aPnt is
        // also adjusted )
        Point aGridOff = CurrentGridSyncOffsetAndPos( aPnt );

        pWindow->CaptureMouse();
        pView->BegCreateObj(aPnt);
        pView->GetCreateObj()->SetGridOffset( aGridOff );
        bReturn = true;
    }
    return bReturn;
diff --git a/sc/source/ui/drawfunc/futext.cxx b/sc/source/ui/drawfunc/futext.cxx
index 13a38a9..ae32909 100644
--- a/sc/source/ui/drawfunc/futext.cxx
+++ b/sc/source/ui/drawfunc/futext.cxx
@@ -295,15 +295,7 @@
                if (bStraightEnter)//Hack for that silly idea that creating text fields is inside the text routine
                {
                    // create object
                    // Hack to align object to nearest grid position where object
                    // would be anchored ( if it were cell anchored )
                    // Get grid offset for current position ( note: aPnt is
                    // also adjusted )
                    Point aGridOff = CurrentGridSyncOffsetAndPos( aMDPos );

                    bool bRet = pView->BegCreateObj(aMDPos);
                    if ( bRet )
                    pView->GetCreateObj()->SetGridOffset( aGridOff );
                    pView->BegCreateObj(aMDPos);
                }
                else if (SdrObject* pObj = pView->PickObj(aMDPos, pView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER | SdrSearchOptions::BEFOREMARK))
                {
@@ -355,11 +347,6 @@

    Point aPix(rMEvt.GetPosPixel());
    Point aPnt(pWindow->PixelToLogic(aPix));
    // if object is being created then more than likely the mouse
    // position has been 'adjusted' for the current zoom, need to
    // restore the mouse position here to ensure resize works as expected
    if ( pView->GetCreateObj() )
        aPnt -= pView->GetCreateObj()->GetGridOffset();

    if ( pView->MouseMove(rMEvt, pWindow) )
        return true; // event handled from SdrView
diff --git a/sc/source/ui/inc/drawview.hxx b/sc/source/ui/inc/drawview.hxx
index ce2af6a..5a79b95 100644
--- a/sc/source/ui/inc/drawview.hxx
+++ b/sc/source/ui/inc/drawview.hxx
@@ -155,10 +155,25 @@
        const OUString& rFilter);

    static void CheckOle( const SdrMarkList& rMarkList, bool& rAnyOle, bool& rOneOle );

    void SyncForGrid( SdrObject* pObj );

    bool calculateGridOffsetForSdrObject(
        SdrObject& rSdrObject,
        basegfx::B2DVector& rTarget) const;
    bool calculateGridOffsetForB2DRange(
        const basegfx::B2DRange& rB2DRange,
        basegfx::B2DVector& rTarget) const;
    void resetGridOffsetsForAllSdrPageViews();

    /// See SdrMarkView::GetSfxViewShell().
    SfxViewShell* GetSfxViewShell() const override;

    // Do not create ObjectContact locally, but offer a call to allow override
    // and to create own derivations of ObjectContact
    virtual sdr::contact::ObjectContact* createViewSpecificObjectContact(
        SdrPageWindow& rPageWindow,
        const sal_Char* pDebugName) const override;
};

extern Point aDragStartDiff;
diff --git a/sc/source/ui/inc/fuconstr.hxx b/sc/source/ui/inc/fuconstr.hxx
index 2dd8f6a..e87a320 100644
--- a/sc/source/ui/inc/fuconstr.hxx
+++ b/sc/source/ui/inc/fuconstr.hxx
@@ -37,10 +37,6 @@
    virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;

            bool SimpleMouseButtonUp(const MouseEvent& rMEvt);

    // Returns grid sync offset for rInOutPos, additionally adjusts rInOutPos
    // by the offset
    Point CurrentGridSyncOffsetAndPos( Point& rInOutPos);
};

#endif      // _SD_FUCONSTR_HXX
diff --git a/sc/source/ui/inc/notemark.hxx b/sc/source/ui/inc/notemark.hxx
index 45a09ed..ee682ad 100644
--- a/sc/source/ui/inc/notemark.hxx
+++ b/sc/source/ui/inc/notemark.hxx
@@ -49,7 +49,6 @@
    bool const        m_bByKeyboard;

    tools::Rectangle       m_aRect;
    ScDrawView*     m_pDrawView;
    std::unique_ptr<SdrModel>           m_pModel;
    std::shared_ptr< SdrCaptionObj >    m_xObject;
    bool            m_bVisible;
@@ -58,7 +57,7 @@
public:
                ScNoteMarker( vcl::Window* pWin, vcl::Window* pRight, vcl::Window* pBottom, vcl::Window* pDiagonal,
                                ScDocument* pD, const ScAddress& aPos, const OUString& rUser,
                                const MapMode& rMap, bool bLeftEdge, bool bForce, bool bKeyboard, ScDrawView * pDrawView);
                                const MapMode& rMap, bool bLeftEdge, bool bForce, bool bKeyboard);
                ~ScNoteMarker();

    void        Draw();
diff --git a/sc/source/ui/view/drawview.cxx b/sc/source/ui/view/drawview.cxx
index 3882c0d..28af22f 100644
--- a/sc/source/ui/view/drawview.cxx
+++ b/sc/source/ui/view/drawview.cxx
@@ -38,6 +38,10 @@
#include <comphelper/lok.hxx>
#include <sfx2/lokhelper.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <svx/sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdr/contact/viewobjectcontact.hxx>
#include <svx/sdr/contact/viewcontact.hxx>
#include <svx/sdrpagewindow.hxx>

#include <drawview.hxx>
#include <global.hxx>
@@ -322,8 +326,13 @@
    if (nEndRow<20)
        nEndRow = 20;

    ScDrawUtil::CalcScale( pDoc, nTab, 0,0, nEndCol,nEndRow, pDev,aZoomX,aZoomY,nPPTX,nPPTY,
                            aScaleX,aScaleY );
    ScDrawUtil::CalcScale(
        pDoc, nTab, 0, 0, nEndCol, nEndRow, pDev, aZoomX, aZoomY, nPPTX, nPPTY,
        aScaleX, aScaleY);

    // clear all evtl existing GridOffset vectors
    resetGridOffsetsForAllSdrPageViews();

    SdrPageView* pPV = GetSdrPageView();
    if ( pViewData && pPV )
    {
@@ -939,7 +948,12 @@
            // synthesise an anchor ( but don't attach it to
            // the object as we want to maintain page anchoring )
            ScDrawObjData aAnchor;
            ScDrawLayer::GetCellAnchorFromPosition( *pObj, aAnchor, *pDoc, GetTab() );
            const tools::Rectangle aObjRect(pObj->GetLogicRect());
            ScDrawLayer::GetCellAnchorFromPosition(
                aObjRect,
                aAnchor,
                *pDoc,
                GetTab());
            aOldStt = aAnchor.maStart;
        }
        MapMode aDrawMode = pGridWin->GetDrawMapMode();
@@ -954,10 +968,138 @@
        // fdo#63878 Fix the X position for RTL Sheet
        if( pDoc->IsNegativePage( GetTab() ) )
            aGridOff.setX( aCurPosHmm.getX() + aOldPos.getX() );
        pObj->SetGridOffset( aGridOff );
    }
}

void ScDrawView::resetGridOffsetsForAllSdrPageViews()
{
    SdrPageView* pPageView(GetSdrPageView());

    if(nullptr != pPageView)
    {
        for(sal_uInt32 a(0); a < pPageView->PageWindowCount(); a++)
        {
            SdrPageWindow* pPageWindow(pPageView->GetPageWindow(a));
            assert(pPageWindow && "SdrView::SetMasterPagePaintCaching: Corrupt SdrPageWindow list (!)");

            if(nullptr != pPageWindow)
            {
                sdr::contact::ObjectContact& rObjectContact(pPageWindow->GetObjectContact());

                if(rObjectContact.supportsGridOffsets())
                {
                    rObjectContact.resetAllGridOffsets();
                }
            }
        }
    }
}

bool ScDrawView::calculateGridOffsetForSdrObject(
    SdrObject& rSdrObject,
    basegfx::B2DVector& rTarget) const
{
    ScGridWindow* pGridWin(pViewData->GetActiveWin());

    if(nullptr == pGridWin)
    {
        return false;
    }

    ScDrawObjData* pData(ScDrawLayer::GetObjData(&rSdrObject));
    ScAddress aOldStt;

    if(nullptr != pData && pData->maStart.IsValid())
    {
        aOldStt = pData->maStart;
    }
    else
    {
        // Page anchored object so...
        // synthesise an anchor ( but don't attach it to
        // the object as we want to maintain page anchoring )
        ScDrawObjData aAnchor;
        const tools::Rectangle aObjRect(rSdrObject.GetLogicRect());
        ScDrawLayer::GetCellAnchorFromPosition(
            aObjRect,
            aAnchor,
            *pDoc,
            GetTab());
        aOldStt = aAnchor.maStart;
    }

    MapMode aDrawMode = pGridWin->GetDrawMapMode();

    // find pos anchor position
    Point aOldPos(pDoc->GetColOffset(aOldStt.Col(), aOldStt.Tab()), pDoc->GetRowOffset(aOldStt.Row(), aOldStt.Tab()));
    aOldPos.setX(sc::TwipsToHMM(aOldPos.X()));
    aOldPos.setY(sc::TwipsToHMM(aOldPos.Y()));

    // find position of same point on the screen ( e.g. grid )
    ScSplitPos eWhich(pViewData->GetActivePart());
    Point aCurPos(pViewData->GetScrPos(aOldStt.Col(), aOldStt.Row(), eWhich, true));
    Point aCurPosHmm(pGridWin->PixelToLogic(aCurPos, aDrawMode));
    Point aGridOff(aCurPosHmm - aOldPos);

    // fdo#63878 Fix the X position for RTL Sheet
    if(pDoc->IsNegativePage(GetTab()))
    {
        aGridOff.setX(aCurPosHmm.getX() + aOldPos.getX());
    }

    rTarget.setX(aGridOff.X());
    rTarget.setY(aGridOff.Y());
    return true;
}

bool ScDrawView::calculateGridOffsetForB2DRange(
    const basegfx::B2DRange& rB2DRange,
    basegfx::B2DVector& rTarget) const
{
    ScGridWindow* pGridWin(pViewData->GetActiveWin());

    if(nullptr == pGridWin || rB2DRange.isEmpty())
    {
        return false;
    }

    // No SdrObject, so synthesise an anchor ( but don't attach it to
    // the object as we want to maintain page anchoring )
    ScDrawObjData aAnchor;
    const tools::Rectangle aRectangle(
        basegfx::fround(rB2DRange.getMinX()), basegfx::fround(rB2DRange.getMinY()),
        basegfx::fround(rB2DRange.getMaxX()), basegfx::fround(rB2DRange.getMaxY()));
    ScDrawLayer::GetCellAnchorFromPosition(
        aRectangle,
        aAnchor,
        *pDoc,
        GetTab());
    ScAddress aOldStt(aAnchor.maStart);

    MapMode aDrawMode = pGridWin->GetDrawMapMode();

    // find pos anchor position
    Point aOldPos(pDoc->GetColOffset(aOldStt.Col(), aOldStt.Tab()), pDoc->GetRowOffset(aOldStt.Row(), aOldStt.Tab()));
    aOldPos.setX(sc::TwipsToHMM(aOldPos.X()));
    aOldPos.setY(sc::TwipsToHMM(aOldPos.Y()));

    // find position of same point on the screen ( e.g. grid )
    ScSplitPos eWhich(pViewData->GetActivePart());
    Point aCurPos(pViewData->GetScrPos(aOldStt.Col(), aOldStt.Row(), eWhich, true));
    Point aCurPosHmm(pGridWin->PixelToLogic(aCurPos, aDrawMode));
    Point aGridOff(aCurPosHmm - aOldPos);

    // fdo#63878 Fix the X position for RTL Sheet
    if(pDoc->IsNegativePage(GetTab()))
    {
        aGridOff.setX(aCurPosHmm.getX() + aOldPos.getX());
    }

    rTarget.setX(aGridOff.X());
    rTarget.setY(aGridOff.Y());
    return true;
}

// support enhanced text edit for draw objects
SdrUndoManager* ScDrawView::getSdrUndoManagerForEnhancedTextEdit() const
{
@@ -1001,4 +1143,87 @@
    return nullptr;
}

// Own derivation of ObjectContact to allow on-demand calculation of
// GridOffset for non-linear ViewToDevice transformation (calc)
namespace sdr
{
    namespace contact
    {
        class ObjectContactOfScDrawView final : public ObjectContactOfPageView
        {
        private:
            // The ScDrawView to work on
            const ScDrawView&       mrScDrawView;

        public:
            explicit ObjectContactOfScDrawView(
                const ScDrawView& rScDrawView,
                SdrPageWindow& rPageWindow,
                const sal_Char* pDebugName);

            virtual bool supportsGridOffsets() const override;
            virtual void calculateGridOffsetForViewOjectContact(
                basegfx::B2DVector& rTarget,
                const ViewObjectContact& rClient) const override;
            virtual void calculateGridOffsetForB2DRange(
                basegfx::B2DVector& rTarget,
                const basegfx::B2DRange& rB2DRange) const override;
        };

        ObjectContactOfScDrawView::ObjectContactOfScDrawView(
            const ScDrawView& rScDrawView,
            SdrPageWindow& rPageWindow,
            const sal_Char* pDebugName)
        :   ObjectContactOfPageView(rPageWindow, pDebugName),
            mrScDrawView(rScDrawView)
        {
        }

        bool ObjectContactOfScDrawView::supportsGridOffsets() const
        {
            // yes - we support it
            return true;
        }

        void ObjectContactOfScDrawView::calculateGridOffsetForViewOjectContact(
            basegfx::B2DVector& rTarget,
            const ViewObjectContact& rClient) const
        {
            // Here the on-demand calculation happens. Try to access the SdrObject involved
            SdrObject* pTargetSdrObject(rClient.GetViewContact().TryToGetSdrObject());

            if(nullptr != pTargetSdrObject)
            {
                mrScDrawView.calculateGridOffsetForSdrObject(
                    *pTargetSdrObject,
                    rTarget);
            }
        }

        void ObjectContactOfScDrawView::calculateGridOffsetForB2DRange(
            basegfx::B2DVector& rTarget,
            const basegfx::B2DRange& rB2DRange) const
        {
            // Here the on-demand calculation happens. Try to access the SdrObject involved
            if(!rB2DRange.isEmpty())
            {
                mrScDrawView.calculateGridOffsetForB2DRange(
                    rB2DRange,
                    rTarget);
            }
        }
    }
}

// Create own derivation of ObjectContact for calc
sdr::contact::ObjectContact* ScDrawView::createViewSpecificObjectContact(
    SdrPageWindow& rPageWindow,
    const sal_Char* pDebugName) const
{
    return new sdr::contact::ObjectContactOfScDrawView(
        *this,
        rPageWindow,
        pDebugName);
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/gridwin3.cxx b/sc/source/ui/view/gridwin3.cxx
index c2ea234..4faefae 100644
--- a/sc/source/ui/view/gridwin3.cxx
+++ b/sc/source/ui/view/gridwin3.cxx
@@ -332,10 +332,6 @@
        pDrView->TakeActionRect( aRect );
        if ( !aRect.IsEmpty() )
        {
            // mouse position will have been adjusted for offset
            // at current position and zoom, restore that adjustment here
            // so status shows correct value
            aRect -= pDrView->GetGridOffset();
            pPV->LogicToPagePos(aRect);
            aSet.Put( SfxPointItem( SID_ATTR_POSITION, aRect.TopLeft() ) );
            aSet.Put( SvxSizeItem( SID_ATTR_SIZE,
@@ -348,10 +344,6 @@
        if ( pDrView->AreObjectsMarked() ) // selected objects
        {
            tools::Rectangle aRect = pDrView->GetAllMarkedRect();
            // mouse position will have been adjusted for offset
            // at current position and zoom, restore that adjustment here
            // so status shows correct value
            aRect -=  pDrView->GetGridOffset();
            pPV->LogicToPagePos(aRect);
            aSet.Put( SfxPointItem( SID_ATTR_POSITION, aRect.TopLeft() ) );
            aSet.Put( SvxSizeItem( SID_ATTR_SIZE,
diff --git a/sc/source/ui/view/gridwin5.cxx b/sc/source/ui/view/gridwin5.cxx
index bcaa4c7..40f3bd7 100644
--- a/sc/source/ui/view/gridwin5.cxx
+++ b/sc/source/ui/view/gridwin5.cxx
@@ -208,7 +208,7 @@

            mpNoteMarker.reset(new ScNoteMarker(pLeft, pRight, pBottom, pDiagonal,
                                                pDoc, aCellPos, aTrackText,
                                                aMapMode, bLeftEdge, bFast, bKeyboard, pViewData->GetScDrawView()));
                                                aMapMode, bLeftEdge, bFast, bKeyboard));
        }

        bDone = true;       // something is shown (old or new)
diff --git a/sc/source/ui/view/notemark.cxx b/sc/source/ui/view/notemark.cxx
index 6e78953..49901c9 100644
--- a/sc/source/ui/view/notemark.cxx
+++ b/sc/source/ui/view/notemark.cxx
@@ -36,7 +36,7 @@

ScNoteMarker::ScNoteMarker( vcl::Window* pWin, vcl::Window* pRight, vcl::Window* pBottom, vcl::Window* pDiagonal,
                            ScDocument* pD, const ScAddress& aPos, const OUString& rUser,
                            const MapMode& rMap, bool bLeftEdge, bool bForce, bool bKeyboard, ScDrawView *pDrawViewP) :
                            const MapMode& rMap, bool bLeftEdge, bool bForce, bool bKeyboard) :
    m_pWindow( pWin ),
    m_pRightWin( pRight ),
    m_pBottomWin( pBottom ),
@@ -47,7 +47,6 @@
    m_aMapMode( rMap ),
    m_bLeft( bLeftEdge ),
    m_bByKeyboard( bKeyboard ),
    m_pDrawView ( pDrawViewP ),
    m_bVisible( false )
{
    Size aSizePixel = m_pWindow->GetOutputSizePixel();
@@ -98,15 +97,14 @@
            m_xObject = ScNoteUtil::CreateTempCaption( *m_pDoc, m_aDocPos, *pPage, m_aUserText, m_aVisRect, m_bLeft );
            if( m_xObject )
            {
                if (m_pDrawView)
                    m_pDrawView->SyncForGrid(m_xObject.get());
                // Here, SyncForGrid and GetGridOffset was used with the comment:
                // // Need to include grid offset: GetCurrentBoundRect is removing it
                // // but we need to know actual rect position
                // This is no longer true - SdrObject::RecalcBoundRect() uses the
                // GetViewContact().getViewIndependentPrimitive2DContainer()) call
                // that now by default adds the eventually needed GridOffset. Thus
                // I have removed that adaption stuff.
                m_aRect = m_xObject->GetCurrentBoundRect();

                // Need to include grid offset: GetCurrentBoundRect is removing it
                // but we need to know actual rect position
                m_aRect += m_xObject->GetGridOffset();

                assert(m_pDrawView && "this ended up with a wrong rectangle");
            }

            // Insert page so that the model recognise it and also deleted
diff --git a/sd/source/ui/animations/motionpathtag.cxx b/sd/source/ui/animations/motionpathtag.cxx
index 47e2f5d..7ca7fc9 100644
--- a/sd/source/ui/animations/motionpathtag.cxx
+++ b/sd/source/ui/animations/motionpathtag.cxx
@@ -290,8 +290,11 @@
                            const drawinglayer::primitive2d::Primitive2DContainer& aSequence = rVC.getViewIndependentPrimitive2DContainer();
                            std::unique_ptr<sdr::overlay::OverlayObject> pNew(new sdr::overlay::OverlayPrimitive2DSequenceObject(aSequence));

                            xManager->add(*pNew);
                            maOverlayGroup.append(std::move(pNew));
                            // OVERLAYMANAGER
                            insertNewlyCreatedOverlayObjectForSdrHdl(
                                std::move(pNew),
                                rPageWindow.GetObjectContact(),
                                *xManager.get());
                        }
                    }
                }
diff --git a/sd/source/ui/annotations/annotationtag.cxx b/sd/source/ui/annotations/annotationtag.cxx
index 9a27599..9a58a17 100644
--- a/sd/source/ui/annotations/annotationtag.cxx
+++ b/sd/source/ui/annotations/annotationtag.cxx
@@ -225,8 +225,11 @@
                                pOverlayObject.reset(new sdr::overlay::OverlayBitmapEx( aPosition, aBitmapEx, 0, 0 ));
                            }

                            xManager->add(*pOverlayObject);
                            maOverlayGroup.append(std::move(pOverlayObject));
                            // OVERLAYMANAGER
                            insertNewlyCreatedOverlayObjectForSdrHdl(
                                std::move(pOverlayObject),
                                rPageWindow.GetObjectContact(),
                                *xManager.get());
                        }
                    }
                }
diff --git a/sd/source/ui/view/viewoverlaymanager.cxx b/sd/source/ui/view/viewoverlaymanager.cxx
index 0174c2b..2f1c148 100644
--- a/sd/source/ui/view/viewoverlaymanager.cxx
+++ b/sd/source/ui/view/viewoverlaymanager.cxx
@@ -34,6 +34,7 @@
#include <svx/sdr/overlay/overlayanimatedbitmapex.hxx>
#include <svx/sdr/overlay/overlaybitmapex.hxx>
#include <svx/sdr/overlay/overlaymanager.hxx>
#include <svx/sdr/contact/objectcontact.hxx>
#include <svx/svxids.hrc>

#include <view/viewoverlaymanager.hxx>
@@ -248,8 +249,12 @@
                    {
                        std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject(
                            new sdr::overlay::OverlayBitmapEx( aPosition, aBitmapEx, 0, 0 ));
                        xManager->add(*pOverlayObject);
                        maOverlayGroup.append(std::move(pOverlayObject));

                        // OVERLAYMANAGER
                        insertNewlyCreatedOverlayObjectForSdrHdl(
                            std::move(pOverlayObject),
                            rPageWindow.GetObjectContact(),
                            *xManager.get());
                    }
                }
            }
diff --git a/solenv/clang-format/blacklist b/solenv/clang-format/blacklist
index 28b3971..d0e0cc7 100644
--- a/solenv/clang-format/blacklist
+++ b/solenv/clang-format/blacklist
@@ -7316,6 +7316,7 @@
include/svx/sdr/contact/displayinfo.hxx
include/svx/sdr/contact/objectcontact.hxx
include/svx/sdr/contact/objectcontactofobjlistpainter.hxx
include/svx/sdr/contact/objectcontactofpageview.hxx
include/svx/sdr/contact/viewcontact.hxx
include/svx/sdr/contact/viewcontactofe3d.hxx
include/svx/sdr/contact/viewcontactofe3dscene.hxx
@@ -14028,7 +14029,6 @@
svx/inc/pch/precompiled_svxcore.hxx
svx/inc/sdr/attribute/sdrfilltextattribute.hxx
svx/inc/sdr/attribute/sdrformtextoutlineattribute.hxx
svx/inc/sdr/contact/objectcontactofpageview.hxx
svx/inc/sdr/contact/viewcontactofe3dcube.hxx
svx/inc/sdr/contact/viewcontactofe3dextrude.hxx
svx/inc/sdr/contact/viewcontactofe3dlathe.hxx
diff --git a/svx/inc/dragmt3d.hxx b/svx/inc/dragmt3d.hxx
index 01d9cd6..c5cd6db 100644
--- a/svx/inc/dragmt3d.hxx
+++ b/svx/inc/dragmt3d.hxx
@@ -77,7 +77,9 @@
    virtual bool EndSdrDrag(bool bCopy) override;

    // for migration from XOR to overlay
    virtual void CreateOverlayGeometry(sdr::overlay::OverlayManager& rOverlayManager) override;
    virtual void CreateOverlayGeometry(
        sdr::overlay::OverlayManager& rOverlayManager,
        const sdr::contact::ObjectContact& rObjectContact) override;
};

// Derivative of SdrDragMethod for spinning 3D objects
diff --git a/svx/inc/sdr/contact/viewcontactofsdrole2obj.hxx b/svx/inc/sdr/contact/viewcontactofsdrole2obj.hxx
index a00b95b..8d94c61 100644
--- a/svx/inc/sdr/contact/viewcontactofsdrole2obj.hxx
+++ b/svx/inc/sdr/contact/viewcontactofsdrole2obj.hxx
@@ -33,8 +33,6 @@
private:
    // #i123539# allow local buffering of chart data (if chart)
    drawinglayer::primitive2d::Primitive2DReference mxChartContent;
    // used to check if we need to re-calc the transformation
    Point maGridOffset;

protected:
    // Create a Object-Specific ViewObjectContact, set ViewContact and
diff --git a/svx/source/engine3d/dragmt3d.cxx b/svx/source/engine3d/dragmt3d.cxx
index 94d2bd2..36971d3 100644
--- a/svx/source/engine3d/dragmt3d.cxx
+++ b/svx/source/engine3d/dragmt3d.cxx
@@ -209,7 +209,9 @@
// Draw the wire frame model

// for migration from XOR to overlay
void E3dDragMethod::CreateOverlayGeometry(sdr::overlay::OverlayManager& rOverlayManager)
void E3dDragMethod::CreateOverlayGeometry(
    sdr::overlay::OverlayManager& rOverlayManager,
    const sdr::contact::ObjectContact& rObjectContact)
{
    const sal_uInt32 nCnt(maGrp.size());
    basegfx::B2DPolyPolygon aResult;
@@ -249,10 +251,14 @@

    if(aResult.count())
    {
        std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
            aResult));
        rOverlayManager.add(*pNew);
        addToOverlayObjectList(std::move(pNew));
        std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(
            new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
                aResult));

        insertNewlyCreatedOverlayObjectForSdrDragMethod(
            std::move(pNew),
            rObjectContact,
            rOverlayManager);
    }
}

diff --git a/svx/source/engine3d/view3d.cxx b/svx/source/engine3d/view3d.cxx
index 8a1b385..e3def1a 100644
--- a/svx/source/engine3d/view3d.cxx
+++ b/svx/source/engine3d/view3d.cxx
@@ -114,22 +114,16 @@

            if(pPV && pPV->PageWindowCount())
            {
                sdr::contact::ObjectContact& rOC = pPV->GetPageWindow(0)->GetObjectContact();
                sdr::contact::DisplayInfo aDisplayInfo;

                // Do not use the last ViewPort set at the OC at the last ProcessDisplay()
                rOC.resetViewPort();

                for(size_t a = 0; a < mnCount; ++a)
                {
                    SdrObject* pObject = mrView.GetMarkedObjectByIndex(a);

                    if(pObject)
                    {
                        sdr::contact::ViewContact& rVC = pObject->GetViewContact();
                        sdr::contact::ViewObjectContact& rVOC = rVC.GetViewObjectContact(rOC);

                        const drawinglayer::primitive2d::Primitive2DContainer aNewSequence(rVOC.getPrimitive2DSequenceHierarchy(aDisplayInfo));
                        // use the view-independent primitive representation (without
                        // evtl. GridOffset, that may be applied to the DragEntry individually)
                        const drawinglayer::primitive2d::Primitive2DContainer aNewSequence(
                            pObject->GetViewContact().getViewIndependentPrimitive2DContainer());
                        maFullOverlay.append(aNewSequence);
                    }
                }
diff --git a/svx/source/sdr/contact/objectcontact.cxx b/svx/source/sdr/contact/objectcontact.cxx
index a4d5207..33839d8 100644
--- a/svx/source/sdr/contact/objectcontact.cxx
+++ b/svx/source/sdr/contact/objectcontact.cxx
@@ -31,6 +31,26 @@

namespace sdr { namespace contact {

bool ObjectContact::supportsGridOffsets() const
{
    // default does not support GridOffset
    return false;
}

void ObjectContact::calculateGridOffsetForViewOjectContact(
    basegfx::B2DVector& /*rTarget*/,
    const ViewObjectContact& /*rClient*/) const
{
    // default does not on-demand calculate GridOffset
}

void ObjectContact::calculateGridOffsetForB2DRange(
    basegfx::B2DVector& /*rTarget*/,
    const basegfx::B2DRange& /*rB2DRange*/) const
{
    // default does not on-demand calculate GridOffset
}

ObjectContact::ObjectContact()
:   maViewObjectContactVector(),
    maPrimitiveAnimator(),
@@ -209,6 +229,18 @@
    }
}

void ObjectContact::resetAllGridOffsets()
{
    const sal_uInt32 nVOCCount(getViewObjectContactCount());

    for(sal_uInt32 a(0); a < nVOCCount; a++)
    {
        ViewObjectContact* pVOC(getViewObjectContact(a));
        assert(pVOC && "ObjectContact: ViewObjectContact list Corrupt (!)");
        pVOC->resetGridOffset();
    }
}

}}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/objectcontactofpageview.cxx b/svx/source/sdr/contact/objectcontactofpageview.cxx
index 6a2247bc..0c6ecf0 100644
--- a/svx/source/sdr/contact/objectcontactofpageview.cxx
+++ b/svx/source/sdr/contact/objectcontactofpageview.cxx
@@ -19,7 +19,7 @@

#include <config_features.h>

#include <sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdr/contact/objectcontactofpageview.hxx>
#include <sdr/contact/viewobjectcontactofunocontrol.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svdpage.hxx>
diff --git a/svx/source/sdr/contact/viewcontact.cxx b/svx/source/sdr/contact/viewcontact.cxx
index 0567ff6..178c50f 100644
--- a/svx/source/sdr/contact/viewcontact.cxx
+++ b/svx/source/sdr/contact/viewcontact.cxx
@@ -25,7 +25,7 @@
#include <basegfx/color/bcolor.hxx>
#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdr/contact/objectcontactofpageview.hxx>
#include <tools/debug.hxx>

namespace sdr { namespace contact {
diff --git a/svx/source/sdr/contact/viewcontactofe3dscene.cxx b/svx/source/sdr/contact/viewcontactofe3dscene.cxx
index 591db036..86ca5f0 100644
--- a/svx/source/sdr/contact/viewcontactofe3dscene.cxx
+++ b/svx/source/sdr/contact/viewcontactofe3dscene.cxx
@@ -244,11 +244,8 @@
void ViewContactOfE3dScene::createObjectTransformation()
{
    // create 2d Object Transformation from relative point in 2d scene to world
    tools::Rectangle aRectangle = GetE3dScene().GetSnapRect();
    // Hack for calc, transform position of object according
    // to current zoom so as objects relative position to grid
    // appears stable
    aRectangle += GetE3dScene().GetGridOffset();
    const tools::Rectangle aRectangle(GetE3dScene().GetSnapRect());

    maObjectTransformation.set(0, 0, aRectangle.getWidth());
    maObjectTransformation.set(1, 1, aRectangle.getHeight());
    maObjectTransformation.set(0, 2, aRectangle.Left());
diff --git a/svx/source/sdr/contact/viewcontactofgraphic.cxx b/svx/source/sdr/contact/viewcontactofgraphic.cxx
index 15de4be..2892b3e 100644
--- a/svx/source/sdr/contact/viewcontactofgraphic.cxx
+++ b/svx/source/sdr/contact/viewcontactofgraphic.cxx
@@ -310,14 +310,10 @@

            // take unrotated snap rect for position and size. Directly use model data, not getBoundRect() or getSnapRect()
            // which will use the primitive data we just create in the near future
            tools::Rectangle rRectangle = GetGrafObject().GetGeoRect();
            // Hack for calc, transform position of object according
            // to current zoom so as objects relative position to grid
            // appears stable
            rRectangle += GetGrafObject().GetGridOffset();
            const tools::Rectangle aRectangle(GetGrafObject().GetGeoRect());
            const ::basegfx::B2DRange aObjectRange(
                rRectangle.Left(), rRectangle.Top(),
                rRectangle.Right(), rRectangle.Bottom());
                aRectangle.Left(), aRectangle.Top(),
                aRectangle.Right(), aRectangle.Bottom());

            // look for mirroring
            const GeoStat& rGeoStat(GetGrafObject().GetGeoStat());
diff --git a/svx/source/sdr/contact/viewcontactofgroup.cxx b/svx/source/sdr/contact/viewcontactofgroup.cxx
index d6a0e98..38afca2 100644
--- a/svx/source/sdr/contact/viewcontactofgroup.cxx
+++ b/svx/source/sdr/contact/viewcontactofgroup.cxx
@@ -71,11 +71,7 @@
            else
            {
                // append an invisible outline for the cases where no visible content exists
                tools::Rectangle aCurrentBoundRect(GetSdrObjGroup().GetLastBoundRect());
                // Hack for calc, transform position of object according
                // to current zoom so as objects relative position to grid
                // appears stable
                aCurrentBoundRect += GetSdrObjGroup().GetGridOffset();
                const tools::Rectangle aCurrentBoundRect(GetSdrObjGroup().GetLastBoundRect());
                const basegfx::B2DRange aCurrentRange(
                    aCurrentBoundRect.Left(), aCurrentBoundRect.Top(),
                    aCurrentBoundRect.Right(), aCurrentBoundRect.Bottom());
diff --git a/svx/source/sdr/contact/viewcontactofsdrcaptionobj.cxx b/svx/source/sdr/contact/viewcontactofsdrcaptionobj.cxx
index 7fc5eff..8fe42c1 100644
--- a/svx/source/sdr/contact/viewcontactofsdrcaptionobj.cxx
+++ b/svx/source/sdr/contact/viewcontactofsdrcaptionobj.cxx
@@ -63,16 +63,10 @@
                    false));

            // take unrotated snap rect (direct model data) for position and size
            tools::Rectangle rRectangle = rCaptionObj.GetGeoRect();
            // Hack for calc, transform position of object according
            // to current zoom so as objects relative position to grid
            // appears stable
            Point aGridOff = rCaptionObj.GetGridOffset();
            rRectangle += aGridOff;

            const tools::Rectangle aRectangle(rCaptionObj.GetGeoRect());
            const ::basegfx::B2DRange aObjectRange(
                rRectangle.Left(), rRectangle.Top(),
                rRectangle.Right(), rRectangle.Bottom());
                aRectangle.Left(), aRectangle.Top(),
                aRectangle.Right(), aRectangle.Bottom());
            const GeoStat& rGeoStat(rCaptionObj.GetGeoStat());

            // fill object matrix
@@ -87,11 +81,8 @@
            double fCornerRadiusY;
            drawinglayer::primitive2d::calculateRelativeCornerRadius(
                rCaptionObj.GetEckenradius(), aObjectRange, fCornerRadiusX, fCornerRadiusY);
            ::basegfx::B2DPolygon aTail = rCaptionObj.getTailPolygon();
            // Hack for calc, transform position of tail according
            // to current zoom so as objects relative position to grid
            // appears stable
            aTail.transform( basegfx::utils::createTranslateB2DHomMatrix( aGridOff.X(), aGridOff.Y() ) );
            const basegfx::B2DPolygon aTail(rCaptionObj.getTailPolygon());

            // create primitive. Always create one (even if invisible) to let the decomposition
            // of SdrCaptionPrimitive2D create needed invisible elements for HitTest and BoundRect
            const drawinglayer::primitive2d::Primitive2DReference xReference(
diff --git a/svx/source/sdr/contact/viewcontactofsdrcircobj.cxx b/svx/source/sdr/contact/viewcontactofsdrcircobj.cxx
index 7104edc..8d79664 100644
--- a/svx/source/sdr/contact/viewcontactofsdrcircobj.cxx
+++ b/svx/source/sdr/contact/viewcontactofsdrcircobj.cxx
@@ -50,11 +50,7 @@
                    false));

            // take unrotated snap rect (direct model data) for position and size
            tools::Rectangle aRectangle = GetCircObj().GetGeoRect();
            // Hack for calc, transform position of object according
            // to current zoom so as objects relative position to grid
            // appears stable
            aRectangle += GetRectObj().GetGridOffset();
            const tools::Rectangle aRectangle(GetCircObj().GetGeoRect());
            const basegfx::B2DRange aObjectRange(
                aRectangle.Left(), aRectangle.Top(),
                aRectangle.Right(), aRectangle.Bottom() );
diff --git a/svx/source/sdr/contact/viewcontactofsdredgeobj.cxx b/svx/source/sdr/contact/viewcontactofsdredgeobj.cxx
index c22d14e..37eb526 100644
--- a/svx/source/sdr/contact/viewcontactofsdredgeobj.cxx
+++ b/svx/source/sdr/contact/viewcontactofsdredgeobj.cxx
@@ -40,12 +40,7 @@

        drawinglayer::primitive2d::Primitive2DContainer ViewContactOfSdrEdgeObj::createViewIndependentPrimitive2DSequence() const
        {
            basegfx::B2DPolygon aEdgeTrack = GetEdgeObj().getEdgeTrack();
            Point aGridOff = GetEdgeObj().GetGridOffset();
            // Hack for calc, transform position of object according
            // to current zoom so as objects relative position to grid
            // appears stable
            aEdgeTrack.transform( basegfx::utils::createTranslateB2DHomMatrix( aGridOff.X(), aGridOff.Y() ) );
            const basegfx::B2DPolygon aEdgeTrack(GetEdgeObj().getEdgeTrack());

            // what to do when no EdgeTrack is provided (HitTest and selectability) ?
            OSL_ENSURE(0 != aEdgeTrack.count(), "Connectors with no geometry are not allowed (!)");
diff --git a/svx/source/sdr/contact/viewcontactofsdrmediaobj.cxx b/svx/source/sdr/contact/viewcontactofsdrmediaobj.cxx
index 9040379..bda8a93 100644
--- a/svx/source/sdr/contact/viewcontactofsdrmediaobj.cxx
+++ b/svx/source/sdr/contact/viewcontactofsdrmediaobj.cxx
@@ -100,11 +100,7 @@
{
    // create range using the model data directly. This is in SdrTextObj::aRect which i will access using
    // GetGeoRect() to not trigger any calculations. It's the unrotated geometry which is okay for MediaObjects ATM.
    tools::Rectangle aRectangle(GetSdrMediaObj().GetGeoRect());
    // Hack for calc, transform position of object according
    // to current zoom so as objects relative position to grid
    // appears stable
    aRectangle += GetSdrMediaObj().GetGridOffset();
    const tools::Rectangle aRectangle(GetSdrMediaObj().GetGeoRect());
    const basegfx::B2DRange aRange(
        aRectangle.Left(), aRectangle.Top(),
        aRectangle.Right(), aRectangle.Bottom());
diff --git a/svx/source/sdr/contact/viewcontactofsdrobj.cxx b/svx/source/sdr/contact/viewcontactofsdrobj.cxx
index d042186..ca8abd6 100644
--- a/svx/source/sdr/contact/viewcontactofsdrobj.cxx
+++ b/svx/source/sdr/contact/viewcontactofsdrobj.cxx
@@ -29,7 +29,7 @@
#include <basegfx/color/bcolor.hxx>
#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
#include <drawinglayer/primitive2d/objectinfoprimitive2d.hxx>
#include <sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdrpagewindow.hxx>
#include <svx/sdrpaintwindow.hxx>
#include <svx/svdhdl.hxx>
diff --git a/svx/source/sdr/contact/viewcontactofsdrobjcustomshape.cxx b/svx/source/sdr/contact/viewcontactofsdrobjcustomshape.cxx
index c3f8666..5c4bb78 100644
--- a/svx/source/sdr/contact/viewcontactofsdrobjcustomshape.cxx
+++ b/svx/source/sdr/contact/viewcontactofsdrobjcustomshape.cxx
@@ -45,13 +45,13 @@

        basegfx::B2DRange ViewContactOfSdrObjCustomShape::getCorrectedTextBoundRect() const
        {
            tools::Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect());
            aObjectBound += GetCustomShapeObj().GetGridOffset();
            const tools::Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect());
            tools::Rectangle aTextBound(aObjectBound);
            GetCustomShapeObj().GetTextBounds(aTextBound);
            aTextBound += GetCustomShapeObj().GetGridOffset();
            basegfx::B2DRange aTextRange(aTextBound.Left(), aTextBound.Top(), aTextBound.Right(), aTextBound.Bottom());
            const basegfx::B2DRange aObjectRange(aObjectBound.Left(), aObjectBound.Top(), aObjectBound.Right(), aObjectBound.Bottom());
            const basegfx::B2DRange aObjectRange(
                aObjectBound.Left(), aObjectBound.Top(),
                aObjectBound.Right(), aObjectBound.Bottom());

            // no need to correct if no extra text range
            if(aTextRange != aObjectRange)
@@ -118,18 +118,8 @@
            const SdrObject* pSdrObjRepresentation = GetCustomShapeObj().GetSdrObjectFromCustomShape();
            bool b3DShape(false);

            Point aGridOff = GetCustomShapeObj().GetGridOffset();

            if(pSdrObjRepresentation)
            {
                // Hack for calc, transform position of object according
                // to current zoom so as objects relative position to grid
                // appears stable
                // TTTT: Need to check what *exactly* this is doing - in it's current
                // form it's indeed pretty much a 'hack' as mentioned above and massively
                // in the way for future changes...
                const_cast< SdrObject* >( pSdrObjRepresentation )->SetGridOffset( aGridOff );

                // tdf#118498 The processing of SdrObjListIter for SdrIterMode::DeepNoGroups
                // did change for 3D-Objects, it now correctly enters and iterates the
                // SdrObjects in the E3dScene (same as for SdrObjGroup). This is more correct
@@ -160,10 +150,10 @@
                {
                    // take unrotated snap rect as default, then get the
                    // unrotated text box. Rotation needs to be done centered
                    tools::Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect());
                    // hack for calc grid sync
                    aObjectBound += GetCustomShapeObj().GetGridOffset();
                    const basegfx::B2DRange aObjectRange(aObjectBound.Left(), aObjectBound.Top(), aObjectBound.Right(), aObjectBound.Bottom());
                    const tools::Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect());
                    const basegfx::B2DRange aObjectRange(
                        aObjectBound.Left(), aObjectBound.Top(),
                        aObjectBound.Right(), aObjectBound.Bottom());

                    // #i101684# get the text range unrotated and absolute to the object range
                    const basegfx::B2DRange aTextRange(getCorrectedTextBoundRect());
diff --git a/svx/source/sdr/contact/viewcontactofsdrole2obj.cxx b/svx/source/sdr/contact/viewcontactofsdrole2obj.cxx
index 9a53816..6a13aae 100644
--- a/svx/source/sdr/contact/viewcontactofsdrole2obj.cxx
+++ b/svx/source/sdr/contact/viewcontactofsdrole2obj.cxx
@@ -60,12 +60,10 @@
basegfx::B2DHomMatrix ViewContactOfSdrOle2Obj::createObjectTransform() const
{
    // take unrotated snap rect (direct model data) for position and size
    tools::Rectangle rRectangle = GetOle2Obj().GetGeoRect();
    // Hack for calc, transform position of object according
    // to current zoom so as objects relative position to grid
    // appears stable
    rRectangle += GetOle2Obj().GetGridOffset();
    const basegfx::B2DRange aObjectRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
    const tools::Rectangle aRectangle(GetOle2Obj().GetGeoRect());
    const basegfx::B2DRange aObjectRange(
        aRectangle.Left(), aRectangle.Top(),
        aRectangle.Right(), aRectangle.Bottom());

    // create object matrix
    const GeoStat& rGeoStat(GetOle2Obj().GetGeoStat());
@@ -100,17 +98,12 @@
        // #i123539# allow buffering and reuse of local chart data to not need to rebuild it
        // on every ViewObjectContact::getPrimitive2DSequence call. TTTT: Not needed for
        // aw080, there this mechanism already works differently
        if(mxChartContent.is()
                // check if we need to update the transformation primitive wrapping the chart
                && maGridOffset == GetOle2Obj().GetGridOffset())
        if(mxChartContent.is())
        {
            xContent = mxChartContent;
        }
        else
        {
            // update grid offset
            const_cast< ViewContactOfSdrOle2Obj* >(this)->maGridOffset = GetOle2Obj().GetGridOffset();

            // try to get chart primitives and chart range directly from xChartModel
            basegfx::B2DRange aChartContentRange;
            const drawinglayer::primitive2d::Primitive2DContainer aChartSequence(
diff --git a/svx/source/sdr/contact/viewcontactofsdrpathobj.cxx b/svx/source/sdr/contact/viewcontactofsdrpathobj.cxx
index 9005b67..28942f7 100644
--- a/svx/source/sdr/contact/viewcontactofsdrpathobj.cxx
+++ b/svx/source/sdr/contact/viewcontactofsdrpathobj.cxx
@@ -74,11 +74,6 @@
                    GetPathObj().getText(0),
                    false));
            basegfx::B2DPolyPolygon aUnitPolyPolygon(GetPathObj().GetPathPoly());
            Point aGridOff = GetPathObj().GetGridOffset();
            // Hack for calc, transform position of object according
            // to current zoom so as objects relative position to grid
            // appears stable
            aUnitPolyPolygon.transform( basegfx::utils::createTranslateB2DHomMatrix( aGridOff.X(), aGridOff.Y() ) );
            sal_uInt32 nPolyCount(ensureGeometry(aUnitPolyPolygon));

            // prepare object transformation and unit polygon (direct model data)
diff --git a/svx/source/sdr/contact/viewcontactofsdrrectobj.cxx b/svx/source/sdr/contact/viewcontactofsdrrectobj.cxx
index f02ba91..34734f9 100644
--- a/svx/source/sdr/contact/viewcontactofsdrrectobj.cxx
+++ b/svx/source/sdr/contact/viewcontactofsdrrectobj.cxx
@@ -47,14 +47,10 @@
            false));

    // take unrotated snap rect (direct model data) for position and size
    tools::Rectangle rRectangle = GetRectObj().GetGeoRect();
    // Hack for calc, transform position of object according
    // to current zoom so as objects relative position to grid
    // appears stable
    rRectangle += GetRectObj().GetGridOffset();
    const tools::Rectangle aRectangle(GetRectObj().GetGeoRect());
    const ::basegfx::B2DRange aObjectRange(
        rRectangle.Left(), rRectangle.Top(),
        rRectangle.Right(), rRectangle.Bottom() );
        aRectangle.Left(), aRectangle.Top(),
        aRectangle.Right(), aRectangle.Bottom() );

    const GeoStat& rGeoStat(GetRectObj().GetGeoStat());

diff --git a/svx/source/sdr/contact/viewcontactofunocontrol.cxx b/svx/source/sdr/contact/viewcontactofunocontrol.cxx
index 547e2eb..78bdce4d 100644
--- a/svx/source/sdr/contact/viewcontactofunocontrol.cxx
+++ b/svx/source/sdr/contact/viewcontactofunocontrol.cxx
@@ -21,7 +21,7 @@

#include <sdr/contact/viewcontactofunocontrol.hxx>
#include <sdr/contact/viewobjectcontactofunocontrol.hxx>
#include <sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdr/contact/displayinfo.hxx>
#include <svx/svdouno.hxx>
#include <svx/svdpagv.hxx>
@@ -94,12 +94,7 @@
        // create range. Use model data directly, not getBoundRect()/getSnapRect; these will use
        // the primitive data themselves in the long run. Use SdrUnoObj's (which is a SdrRectObj)
        // call to GetGeoRect() to access SdrTextObj::aRect directly and without executing anything
        tools::Rectangle aRectangle(GetSdrUnoObj().GetGeoRect());
        // Hack for calc, transform position of object according
        // to current zoom so as objects relative position to grid
        // appears stable
        Point aGridOffset = GetSdrUnoObj().GetGridOffset();
        aRectangle += aGridOffset;
        const tools::Rectangle aRectangle(GetSdrUnoObj().GetGeoRect());
        const basegfx::B2DRange aRange(
            aRectangle.Left(), aRectangle.Top(),
            aRectangle.Right(), aRectangle.Bottom());
diff --git a/svx/source/sdr/contact/viewobjectcontact.cxx b/svx/source/sdr/contact/viewobjectcontact.cxx
index e300703..197113c 100644
--- a/svx/source/sdr/contact/viewobjectcontact.cxx
+++ b/svx/source/sdr/contact/viewobjectcontact.cxx
@@ -36,8 +36,8 @@
#include <drawinglayer/processor2d/baseprocessor2d.hxx>
#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
#include <svx/svdoole2.hxx>

#include <sdr/contact/viewcontactofsdrole2obj.hxx>
#include <drawinglayer/primitive2d/transformprimitive2d.hxx>

using namespace com::sun::star;

@@ -159,6 +159,7 @@
    mrViewContact(rViewContact),
    maObjectRange(),
    mxPrimitive2DSequence(),
    maGridOffset(0.0, 0.0),
    mbLazyInvalidate(false)
{
    // make the ViewContact remember me
@@ -363,8 +364,36 @@

        // always update object range when PrimitiveSequence changes
        const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D());
        const_cast< ViewObjectContact* >(this)->maObjectRange =
            mxPrimitive2DSequence.getB2DRange(rViewInformation2D);
        const_cast< ViewObjectContact* >(this)->maObjectRange = mxPrimitive2DSequence.getB2DRange(rViewInformation2D);

        // check and eventually embed to GridOffset transform primitive
        if(GetObjectContact().supportsGridOffsets())
        {
            const basegfx::B2DVector& rGridOffset(getGridOffset());

            if(0.0 != rGridOffset.getX() || 0.0 != rGridOffset.getY())
            {
                const basegfx::B2DHomMatrix aTranslateGridOffset(
                    basegfx::utils::createTranslateB2DHomMatrix(
                        rGridOffset));
                const drawinglayer::primitive2d::Primitive2DReference aEmbed(
                    new drawinglayer::primitive2d::TransformPrimitive2D(
                        aTranslateGridOffset,
                        mxPrimitive2DSequence));

                // Set values at local data. So for now, the mechanism is to reset some of the
                // defining things (mxPrimitive2DSequence, maGridOffset) and re-create the
                // buffered data (including maObjectRange). It *could* be changed to keep
                // the unmodified PrimitiveSequence and only update the GridOffset, but this
                // would require a 2nd instance of maObjectRange and mxPrimitive2DSequence. I
                // started doing so, but it just makes the code more complicated. For now,
                // just allow re-creation of the PrimitiveSequence (and removing buffered
                // decomposed content of it). May be optimized, though. OTOH it only happens
                // in calc which traditionally does not have a huge amout of DrawObjects anyways.
                const_cast< ViewObjectContact* >(this)->mxPrimitive2DSequence = drawinglayer::primitive2d::Primitive2DContainer { aEmbed };
                const_cast< ViewObjectContact* >(this)->maObjectRange.transform(aTranslateGridOffset);
            }
        }
    }

    // return current Primitive2DContainer
@@ -427,6 +456,30 @@
    return xSeqRetval;
}

// Support getting a GridOffset per object and view for non-linear ViewToDevice
// transformation (calc). On-demand created by delegating to the ObjectContact
// (->View) that has then all needed information
const basegfx::B2DVector& ViewObjectContact::getGridOffset() const
{
    if(0.0 == maGridOffset.getX() && 0.0 == maGridOffset.getY() && GetObjectContact().supportsGridOffsets())
    {
        // create on-demand
        GetObjectContact().calculateGridOffsetForViewOjectContact(const_cast<ViewObjectContact*>(this)->maGridOffset, *this);
    }

    return maGridOffset;
}

void ViewObjectContact::resetGridOffset()
{
    // reset buffered GridOffset itself
    maGridOffset.setX(0.0);
    maGridOffset.setY(0.0);

    // also reset sequence to get a re-calculation when GridOffset changes
    mxPrimitive2DSequence.clear();
}

}}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/sdr/contact/viewobjectcontactofsdrobj.cxx b/svx/source/sdr/contact/viewobjectcontactofsdrobj.cxx
index f0c545e..c6183a2 100644
--- a/svx/source/sdr/contact/viewobjectcontactofsdrobj.cxx
+++ b/svx/source/sdr/contact/viewobjectcontactofsdrobj.cxx
@@ -22,7 +22,7 @@
#include <svx/sdr/contact/viewcontactofsdrobj.hxx>
#include <svx/sdr/contact/objectcontact.hxx>
#include <svx/sdr/contact/displayinfo.hxx>
#include <sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdr/contact/objectcontactofpageview.hxx>
#include <sdr/contact/viewcontactofsdrole2obj.hxx>
#include <svx/sdrpagewindow.hxx>
#include <svx/sdrpaintwindow.hxx>
diff --git a/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx b/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
index c785a6c..50dcbd2 100644
--- a/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
+++ b/svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
@@ -22,7 +22,7 @@
#include <sdr/contact/viewcontactofunocontrol.hxx>
#include <svx/sdr/contact/displayinfo.hxx>
#include <svx/sdr/properties/properties.hxx>
#include <sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
#include <svx/svdouno.hxx>
#include <svx/svdpagv.hxx>
@@ -918,12 +918,7 @@
            SdrUnoObj* pUnoObject( nullptr );
            if ( getUnoObject( pUnoObject ) )
            {
                Point aGridOffset = pUnoObject->GetGridOffset();
                tools::Rectangle aRect( pUnoObject->GetLogicRect() );
                // Hack for calc, transform position of object according
                // to current zoom so as objects relative position to grid
                // appears stable
                aRect += aGridOffset;
                const tools::Rectangle aRect( pUnoObject->GetLogicRect() );
                UnoControlContactHelper::adjustControlGeometry_throw( m_aControl, aRect, _rViewTransformation, m_aZoomLevelNormalization );
            }
            else
@@ -1086,12 +1081,7 @@

            // knit the model and the control
            _out_rControl.setModel( xControlModel );
            Point aGridOffset =  _rUnoObject.GetGridOffset();
            tools::Rectangle aRect( _rUnoObject.GetLogicRect() );
            // Hack for calc, transform position of object according
            // to current zoom so as objects relative position to grid
            // appears stable
            aRect += aGridOffset;
            const tools::Rectangle aRect( _rUnoObject.GetLogicRect() );

            // proper geometry
            UnoControlContactHelper::adjustControlGeometry_throw(
@@ -1488,12 +1478,7 @@
        // Do use model data directly to create the correct geometry. Do NOT
        // use getBoundRect()/getSnapRect() here; these will use the sequence of
        // primitives themselves in the long run.
        tools::Rectangle aSdrGeoData( _rVOC.GetSdrUnoObj().GetGeoRect() );
        Point aGridOffset = _rVOC.GetSdrUnoObj().GetGridOffset();
        // Hack for calc, transform position of object according
        // to current zoom so as objects relative position to grid
        // appears stable
        aSdrGeoData += aGridOffset;
        const tools::Rectangle aSdrGeoData( _rVOC.GetSdrUnoObj().GetGeoRect() );
        const basegfx::B2DRange aRange(
            aSdrGeoData.Left(),
            aSdrGeoData.Top(),
diff --git a/svx/source/sdr/overlay/overlayobject.cxx b/svx/source/sdr/overlay/overlayobject.cxx
index aae05f9..d480007 100644
--- a/svx/source/sdr/overlay/overlayobject.cxx
+++ b/svx/source/sdr/overlay/overlayobject.cxx
@@ -26,8 +26,9 @@
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>

#include <drawinglayer/primitive2d/transformprimitive2d.hxx>

namespace sdr
{
@@ -37,7 +38,8 @@
        {
            const basegfx::B2DRange aPreviousRange(maBaseRange);
            maBaseRange.reset();
            setPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DContainer());
            resetPrimitive2DSequence();
//            setPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DContainer());

            if(getOverlayManager() && !aPreviousRange.isEmpty())
            {
@@ -91,6 +93,8 @@
        OverlayObject::OverlayObject(Color aBaseColor)
        :   Event(),
            mpOverlayManager(nullptr),
            maPrimitive2DSequence(),
            maOffset(0.0, 0.0),
            maBaseColor(aBaseColor),
            mbIsVisible(true),
            mbIsHittable(true),
@@ -109,8 +113,21 @@
            if(getPrimitive2DSequence().empty())
            {
                // no existing sequence; create one
                const_cast< OverlayObject* >(this)->setPrimitive2DSequence(
                    const_cast< OverlayObject* >(this)->createOverlayObjectPrimitive2DSequence());
                const_cast< OverlayObject* >(this)->maPrimitive2DSequence = const_cast< OverlayObject* >(this)->createOverlayObjectPrimitive2DSequence();

                if(!getOffset().equalZero())
                {
                    // embed to offset transformation
                    const basegfx::B2DHomMatrix aTranslateGridOffset(
                        basegfx::utils::createTranslateB2DHomMatrix(
                            getOffset()));
                    const drawinglayer::primitive2d::Primitive2DReference aEmbed(
                        new drawinglayer::primitive2d::TransformPrimitive2D(
                            aTranslateGridOffset,
                            maPrimitive2DSequence));

                    const_cast< OverlayObject* >(this)->maPrimitive2DSequence = drawinglayer::primitive2d::Primitive2DContainer { aEmbed };
                }
            }

            return getPrimitive2DSequence();
@@ -170,6 +187,18 @@
            }
        }

        void OverlayObject::setOffset(const basegfx::B2DVector& rOffset)
        {
            if(rOffset != maOffset)
            {
                // remember new value
                maOffset = rOffset;

                // register change (after change)
                objectChange();
            }
        }

        void OverlayObject::Trigger(sal_uInt32 /*nTime*/)
        {
            // default does not register again
diff --git a/svx/source/sdr/overlay/overlayselection.cxx b/svx/source/sdr/overlay/overlayselection.cxx
index 5d22203..a1fa528 100644
--- a/svx/source/sdr/overlay/overlayselection.cxx
+++ b/svx/source/sdr/overlay/overlayselection.cxx
@@ -196,7 +196,7 @@
                    || nNewTransparence != mnLastTransparence)
                {
                    // conditions of last local decomposition have changed, delete
                    const_cast< OverlaySelection* >(this)->setPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DContainer());
                    const_cast< OverlaySelection* >(this)->resetPrimitive2DSequence();
                }
            }

diff --git a/svx/source/svdraw/sdrpagewindow.cxx b/svx/source/svdraw/sdrpagewindow.cxx
index c722fa88..80369f6 100644
--- a/svx/source/svdraw/sdrpagewindow.cxx
+++ b/svx/source/svdraw/sdrpagewindow.cxx
@@ -32,7 +32,7 @@
#include <svx/svdview.hxx>
#include <svx/svdpagv.hxx>
#include <svx/sdrpaintwindow.hxx>
#include <sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdr/contact/displayinfo.hxx>
#include <svx/fmview.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
@@ -43,7 +43,7 @@
struct SdrPageWindow::Impl
{
    // #110094# ObjectContact section
    mutable sdr::contact::ObjectContactOfPageView* mpObjectContact;
    mutable sdr::contact::ObjectContact* mpObjectContact;

    // the SdrPageView this window belongs to
    SdrPageView& mrPageView;
@@ -456,8 +456,11 @@
const sdr::contact::ObjectContact& SdrPageWindow::GetObjectContact() const
{
    if (!mpImpl->mpObjectContact)
        mpImpl->mpObjectContact = new sdr::contact::ObjectContactOfPageView(
            const_cast<SdrPageWindow&>(*this), "svx::svdraw::SdrPageWindow mpObjectContact" );
    {
        mpImpl->mpObjectContact = GetPageView().GetView().createViewSpecificObjectContact(
            const_cast<SdrPageWindow&>(*this),
            "svx::svdraw::SdrPageWindow mpObjectContact");
    }

    return *mpImpl->mpObjectContact;
}
@@ -465,8 +468,11 @@
sdr::contact::ObjectContact& SdrPageWindow::GetObjectContact()
{
    if (!mpImpl->mpObjectContact)
        mpImpl->mpObjectContact = new sdr::contact::ObjectContactOfPageView(
             *this, "svx::svdraw::SdrPageWindow mpObjectContact" );
    {
        mpImpl->mpObjectContact = GetPageView().GetView().createViewSpecificObjectContact(
             *this,
             "svx::svdraw::SdrPageWindow mpObjectContact" );
    }

    return *mpImpl->mpObjectContact;
}
diff --git a/svx/source/svdraw/svdcrtv.cxx b/svx/source/svdraw/svdcrtv.cxx
index 5578cb1..9114810 100644
--- a/svx/source/svdraw/svdcrtv.cxx
+++ b/svx/source/svdraw/svdcrtv.cxx
@@ -641,6 +641,31 @@

                if(!bSceneIntoScene)
                {
                    // Here an interactively created SdrObject gets added, so
                    // take into account that interaction created an object in
                    // model coordinates. If we have e.g. a GirdOffset, this is a
                    // little bit tricky - we have an object in model coordinates,
                    // so the fetched offset is at the wrong point in principle
                    // since we need to 'substract' the offset here to get to
                    // 'real' model coordinates. But we have nothing better here,
                    // so go for it.
                    // The 2nd a little tricky thing is that this will early-create
                    // a ViewObjectContact for the new SdrObject, but these VOCs
                    // are anyways layouted for being create-on-demand. This will
                    // be adapted/replaced corretly later on.
                    // This *should* be the right place for getting all interactively
                    // created objects, see InsertObjectAtView below that calls
                    // CreateUndoNewObject.
                    basegfx::B2DVector aGridOffset(0.0, 0.0);
                    if(getPossibleGridOffsetForSdrObject(aGridOffset, pObj, pCreatePV))
                    {
                        const Size aOffset(
                            basegfx::fround(-aGridOffset.getX()),
                            basegfx::fround(-aGridOffset.getY()));

                        pObj->NbcMove(aOffset);
                    }

                    // do the same as before
                    InsertObjectAtView(pObj, *pCreatePV);
                }
@@ -802,12 +827,8 @@
            }
            else
            {
                ::basegfx::B2DPolyPolygon aPoly = pCurrentCreate->TakeCreatePoly(maDragStat);
                Point aGridOff = pCurrentCreate->GetGridOffset();
                // Hack for calc, transform position of create placeholder
                // object according to current zoom so as objects relative
                // position to grid appears stable
                aPoly.transform( basegfx::utils::createTranslateB2DHomMatrix( aGridOff.X(), aGridOff.Y() ) );
                const ::basegfx::B2DPolyPolygon aPoly(pCurrentCreate->TakeCreatePoly(maDragStat));

                mpCreateViewExtraData->CreateAndShowOverlay(*this, nullptr, aPoly);
            }

diff --git a/svx/source/svdraw/svddrgmt.cxx b/svx/source/svdraw/svddrgmt.cxx
index 2c89ca4a..13ee857 100644
--- a/svx/source/svdraw/svddrgmt.cxx
+++ b/svx/source/svdraw/svddrgmt.cxx
@@ -135,11 +135,12 @@
}


SdrDragEntrySdrObject::SdrDragEntrySdrObject(const SdrObject& rOriginal, sdr::contact::ObjectContact& rObjectContact, bool bModify)
SdrDragEntrySdrObject::SdrDragEntrySdrObject(
    const SdrObject& rOriginal,
    bool bModify)
:   SdrDragEntry(),
    maOriginal(rOriginal),
    mpClone(nullptr),
    mrObjectContact(rObjectContact),
    mbModify(bModify)
{
    // add SdrObject parts to transparent overlay stuff
@@ -185,16 +186,9 @@
        pSource = mpClone;
    }

    // get VOC and Primitive2DContainer
    sdr::contact::ViewContact& rVC = pSource->GetViewContact();
    sdr::contact::ViewObjectContact& rVOC = rVC.GetViewObjectContact(mrObjectContact);
    sdr::contact::DisplayInfo aDisplayInfo;

    // Do not use the last ViewPort set at the OC from the last ProcessDisplay(),
    // here we want the complete primitive sequence without visibility clippings
    mrObjectContact.resetViewPort();

    return rVOC.getPrimitive2DSequenceHierarchy(aDisplayInfo);
    // use the view-independent primitive representation (without
    // evtl. GridOffset, that may be applied to the DragEntry individually)
    return pSource->GetViewContact().getViewIndependentPrimitive2DContainer();
}


@@ -338,11 +332,46 @@
    }
}

void SdrDragMethod::createSdrDragEntryForSdrObject(const SdrObject& rOriginal, sdr::contact::ObjectContact& rObjectContact)
void SdrDragMethod::createSdrDragEntryForSdrObject(const SdrObject& rOriginal)
{
    // add full object drag; Clone() at the object has to work
    // for this
    addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntrySdrObject(rOriginal, rObjectContact, true/*bModify*/)));
    addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntrySdrObject(rOriginal, true/*bModify*/)));
}

void SdrDragMethod::insertNewlyCreatedOverlayObjectForSdrDragMethod(
    std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject,
    const sdr::contact::ObjectContact& rObjectContact,
    sdr::overlay::OverlayManager& rOverlayManager)
{
    // check if we have an OverlayObject
    if(!pOverlayObject)
    {
        return;
    }

    // add to OverlayManager
    rOverlayManager.add(*pOverlayObject);

    // Add GridOffset for non-linear ViewToDevice transformation (calc)
    if(rObjectContact.supportsGridOffsets())
    {
        const basegfx::B2DRange& rNewRange(pOverlayObject->getBaseRange());

        if(!rNewRange.isEmpty())
        {
            basegfx::B2DVector aOffset(0.0, 0.0);
            rObjectContact.calculateGridOffsetForB2DRange(aOffset, rNewRange);

            if(!aOffset.equalZero())
            {
                pOverlayObject->setOffset(aOffset);
            }
        }
    }

    // add to local OverlayObjectList - ownership change (!)
    maOverlayObjectList.append(std::move(pOverlayObject));
}

void SdrDragMethod::createSdrDragEntries_SolidDrag()
@@ -364,7 +393,6 @@
                {
                    if(pPV->PageWindowCount())
                    {
                        sdr::contact::ObjectContact& rOC = pPV->GetPageWindow(0)->GetObjectContact();
                        SdrObjListIter aIter(*pObject);

                        while(aIter.IsMore())
@@ -386,7 +414,7 @@
                                {
                                    // add full object drag; Clone() at the object has to work
                                    // for this
                                    createSdrDragEntryForSdrObject(*pCandidate, rOC);
                                    createSdrDragEntryForSdrObject(*pCandidate);
                                }

                                if(bAddWireframe)
@@ -654,7 +682,9 @@

typedef std::map< const SdrObject*, SdrObject* > SdrObjectAndCloneMap;

void SdrDragMethod::CreateOverlayGeometry(sdr::overlay::OverlayManager& rOverlayManager)
void SdrDragMethod::CreateOverlayGeometry(
    sdr::overlay::OverlayManager& rOverlayManager,
    const sdr::contact::ObjectContact& rObjectContact)
{
    // create SdrDragEntries on demand
    if(maSdrDragEntries.empty())
@@ -764,9 +794,14 @@

        if(!aResult.empty())
        {
            std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new sdr::overlay::OverlayPrimitive2DSequenceObject(aResult));
            rOverlayManager.add(*pNewOverlayObject);
            addToOverlayObjectList(std::move(pNewOverlayObject));
            std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
                new sdr::overlay::OverlayPrimitive2DSequenceObject(
                    aResult));

            insertNewlyCreatedOverlayObjectForSdrDragMethod(
                std::move(pNewOverlayObject),
                rObjectContact,
                rOverlayManager);
        }

        if(!aResultTransparent.empty())
@@ -774,9 +809,14 @@
            drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparencePrimitive2D(new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(aResultTransparent, 0.5));
            aResultTransparent = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparencePrimitive2D };

            std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(new sdr::overlay::OverlayPrimitive2DSequenceObject(aResultTransparent));
            rOverlayManager.add(*pNewOverlayObject);
            addToOverlayObjectList(std::move(pNewOverlayObject));
            std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
                new sdr::overlay::OverlayPrimitive2DSequenceObject(
                    aResultTransparent));

            insertNewlyCreatedOverlayObjectForSdrDragMethod(
                std::move(pNewOverlayObject),
                rObjectContact,
                rOverlayManager);
        }
    }

@@ -788,11 +828,17 @@

        const basegfx::B2DPoint aTopLeft(aActionRectangle.Left(), aActionRectangle.Top());
        const basegfx::B2DPoint aBottomRight(aActionRectangle.Right(), aActionRectangle.Bottom());
        std::unique_ptr<sdr::overlay::OverlayRollingRectangleStriped> pNew(new sdr::overlay::OverlayRollingRectangleStriped(
            aTopLeft, aBottomRight, true, false));
        std::unique_ptr<sdr::overlay::OverlayRollingRectangleStriped> pNew(
            new sdr::overlay::OverlayRollingRectangleStriped(
                aTopLeft,
                aBottomRight,
                true,
                false));

        rOverlayManager.add(*pNew);
        addToOverlayObjectList(std::move(pNew));
        insertNewlyCreatedOverlayObjectForSdrDragMethod(
            std::move(pNew),
            rObjectContact,
            rOverlayManager);
    }
}

@@ -1159,8 +1205,7 @@

            if(pPV && pPV->PageWindowCount())
            {
                sdr::contact::ObjectContact& rOC = pPV->GetPageWindow(0)->GetObjectContact();
                addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntrySdrObject(*mpClone, rOC, false)));
                addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntrySdrObject(*mpClone, false)));

                // potentially no wireframe needed, full drag works
                bAddWireframe = false;
@@ -1417,19 +1462,15 @@
}


void SdrDragMove::createSdrDragEntryForSdrObject(const SdrObject& rOriginal, sdr::contact::ObjectContact& rObjectContact)
void SdrDragMove::createSdrDragEntryForSdrObject(const SdrObject& rOriginal)
{
    // for SdrDragMove, use current Primitive2DContainer of SdrObject visualization
    // in given ObjectContact directly
    sdr::contact::ViewContact& rVC = rOriginal.GetViewContact();
    sdr::contact::ViewObjectContact& rVOC = rVC.GetViewObjectContact(rObjectContact);
    sdr::contact::DisplayInfo aDisplayInfo;
    // use the view-independent primitive representation (without
    // evtl. GridOffset, that may be applied to the DragEntry individually)
    addSdrDragEntry(
        std::unique_ptr<SdrDragEntry>(
            new SdrDragEntryPrimitive2DSequence(
                rOriginal.GetViewContact().getViewIndependentPrimitive2DContainer())));

    // Do not use the last ViewPort set at the OC from the last ProcessDisplay(),
    // here we want the complete primitive sequence without visible clippings
    rObjectContact.resetViewPort();

    addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPrimitive2DSequence(rVOC.getPrimitive2DSequenceHierarchy(aDisplayInfo))));
}

void SdrDragMove::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
@@ -1766,8 +1807,7 @@

    if (pRefHdl!=nullptr && !getSdrDragView().IsResizeAtCenter())
    {
        // Calc hack to adjust for calc grid
        DragStat().SetRef1(pRefHdl->GetPos() - getSdrDragView().GetGridOffset());
        DragStat().SetRef1(pRefHdl->GetPos());
    }
    else
    {
diff --git a/svx/source/svdraw/svddrgv.cxx b/svx/source/svdraw/svddrgv.cxx
index 20f14af..31132a5 100644
--- a/svx/source/svdraw/svddrgv.cxx
+++ b/svx/source/svdraw/svddrgv.cxx
@@ -40,6 +40,7 @@
#include <svx/polypolygoneditor.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <svx/sdr/overlay/overlaymanager.hxx>
#include <svx/sdrpagewindow.hxx>

using namespace sdr;

@@ -220,6 +221,19 @@
        }

        Point aPnt(rPnt);
        basegfx::B2DVector aGridOffset(0.0, 0.0);

        // Coordinate maybe affected by GridOffset, so we may need to
        // adapt to Model-coordinates here
        if(getPossibleGridOffsetForPosition(
            aGridOffset,
            basegfx::B2DPoint(aPnt.X(), aPnt.Y()),
            GetSdrPageView()))
        {
            aPnt.AdjustX(basegfx::fround(-aGridOffset.getX()));
            aPnt.AdjustY(basegfx::fround(-aGridOffset.getY()));
        }

        if(pHdl == nullptr
            || pHdl->GetKind() == SdrHdlKind::Move
            || pHdl->GetKind() == SdrHdlKind::MirrorAxis
@@ -508,6 +522,19 @@
    if (mpCurrentSdrDragMethod)
    {
        Point aPnt(rPnt);
        basegfx::B2DVector aGridOffset(0.0, 0.0);

        // Coordinate maybe affected by GridOffset, so we may need to
        // adapt to Model-coordinates here
        if(getPossibleGridOffsetForPosition(
            aGridOffset,
            basegfx::B2DPoint(aPnt.X(), aPnt.Y()),
            GetSdrPageView()))
        {
            aPnt.AdjustX(basegfx::fround(-aGridOffset.getX()));
            aPnt.AdjustY(basegfx::fround(-aGridOffset.getY()));
        }

        ImpLimitToWorkArea(aPnt);
        mpCurrentSdrDragMethod->MoveSdrDrag(aPnt); // this call already makes a Hide()/Show combination
    }
@@ -780,17 +807,35 @@
{
    if(mpCurrentSdrDragMethod && !maDragStat.IsShown())
    {
        for(sal_uInt32 a(0); a < PaintWindowCount(); a++)
        // Changed for the GridOffset stuff: No longer iterate over
        // SdrPaintWindow(s), but now over SdrPageWindow(s), so doing the
        // same as the SdrHdl visualizations (see ::CreateB2dIAObject) do.
        // This is needed to get access to a ObjectContact which is needed
        // to evtl. process that GridOffset in CreateOverlayGeometry
        SdrPageView* pPageView(GetSdrPageView());

        if(nullptr != pPageView)
        {
            SdrPaintWindow* pCandidate = GetPaintWindow(a);
            const rtl::Reference<sdr::overlay::OverlayManager>& xOverlayManager = pCandidate->GetOverlayManager();

            if (xOverlayManager.is())
            for(sal_uInt32 a(0); a < pPageView->PageWindowCount(); a++)
            {
                mpCurrentSdrDragMethod->CreateOverlayGeometry(*xOverlayManager);
                const SdrPageWindow& rPageWindow(*pPageView->GetPageWindow(a));
                const SdrPaintWindow& rPaintWindow(rPageWindow.GetPaintWindow());

                // #i101679# Force changed overlay to be shown
                xOverlayManager->flush();
                if(rPaintWindow.OutputToWindow())
                {
                    const rtl::Reference<sdr::overlay::OverlayManager>& xOverlayManager(
                        rPaintWindow.GetOverlayManager());

                    if(xOverlayManager.is())
                    {
                        mpCurrentSdrDragMethod->CreateOverlayGeometry(
                            *xOverlayManager.get(),
                            rPageWindow.GetObjectContact());

                        // #i101679# Force changed overlay to be shown
                        xOverlayManager->flush();
                    }
                }
            }
        }

diff --git a/svx/source/svdraw/svdedtv1.cxx b/svx/source/svdraw/svdedtv1.cxx
index 960dd2c..1acf37c 100644
--- a/svx/source/svdraw/svdedtv1.cxx
+++ b/svx/source/svdraw/svdedtv1.cxx
@@ -1259,8 +1259,6 @@
    {
        SfxItemSet aMarkAttr(GetAttrFromMarked(false)); // because of AutoGrowHeight and corner radius
        tools::Rectangle aRect(GetMarkedObjRect());
        // restore position to that before calc hack
        aRect -= GetGridOffset();

        if(GetSdrPageView())
        {
diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx
index 0f7361b..66a409c 100644
--- a/svx/source/svdraw/svdedxv.cxx
+++ b/svx/source/svdraw/svdedxv.cxx
@@ -261,13 +261,20 @@
                tools::Rectangle aEditArea1;
                tools::Rectangle aMinArea1;
                pTextObj->TakeTextEditArea(&aPaperMin1,&aPaperMax1,&aEditArea1,&aMinArea1);

                Point aPvOfs(pTextObj->GetTextEditOffset());
                // Hack for calc, transform position of edit object according
                // to current zoom so as objects relative position to grid
                // appears stable
                aEditArea1 += pTextObj->GetGridOffset();
                aMinArea1 += pTextObj->GetGridOffset();

                // add possible GridOffset to up-to-now view-independent EditAreas
                basegfx::B2DVector aGridOffset(0.0, 0.0);
                if(getPossibleGridOffsetForSdrObject(aGridOffset, pTextObj, GetSdrPageView()))
                {
                    const Point aOffset(
                        basegfx::fround(aGridOffset.getX()),
                        basegfx::fround(aGridOffset.getY()));

                    aEditArea1 += aOffset;
                    aMinArea1 += aOffset;
                }

                aEditArea1.Move(aPvOfs.X(),aPvOfs.Y());
                aMinArea1.Move(aPvOfs.X(),aPvOfs.Y());
                tools::Rectangle aNewArea(aMinArea1);
@@ -494,7 +501,7 @@
            if (!maRange.equal(maLastRange) || maLastTextPrimitives != maTextPrimitives)
            {
                // conditions of last local decomposition have changed, delete to force new evaluation
                const_cast<TextEditOverlayObject*>(this)->setPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DContainer());
                const_cast<TextEditOverlayObject*>(this)->resetPrimitive2DSequence();
            }
        }

@@ -1148,14 +1155,20 @@

            aTextEditArea = aTextRect;

            // Hack for calc, transform position of edit object according
            // to current zoom so as objects relative position to grid
            // appears stable
            // add possible GridOffset to up-to-now view-independent EditAreas
            basegfx::B2DVector aGridOffset(0.0, 0.0);
            if(getPossibleGridOffsetForSdrObject(aGridOffset, pTextObj, pPV))
            {
                const Point aOffset(
                    basegfx::fround(aGridOffset.getX()),
                    basegfx::fround(aGridOffset.getY()));

                aTextEditArea += aOffset;
                aMinTextEditArea += aOffset;
            }

            Point aPvOfs(pTextObj->GetTextEditOffset());
            aTextEditArea += pTextObj->GetGridOffset();
            aTextEditArea.Move(aPvOfs.X(),aPvOfs.Y());
            aMinTextEditArea += pTextObj->GetGridOffset();
            aMinTextEditArea.Move(aPvOfs.X(),aPvOfs.Y());
            pTextEditCursorBuffer=pWin->GetCursor();

diff --git a/svx/source/svdraw/svdhdl.cxx b/svx/source/svdraw/svdhdl.cxx
index 93621e7..0a51a0a 100644
--- a/svx/source/svdraw/svdhdl.cxx
+++ b/svx/source/svdraw/svdhdl.cxx
@@ -56,6 +56,8 @@
#include <svx/sdr/overlay/overlaypolypolygon.hxx>
#include <vcl/lazydelete.hxx>
#include <vcl/BitmapTools.hxx>
#include <svx/sdr/contact/objectcontact.hxx>
#include <svx/sdr/contact/viewcontact.hxx>

#include <basegfx/polygon/b2dpolygontools.hxx>
#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
@@ -612,12 +614,12 @@
                                                    aPosition, eColIndex, eKindOfMarker,
                                                    aMoveOutsideOffset);
                        }

                        // OVERLAYMANAGER
                        if (pNewOverlayObject)
                        {
                            xManager->add(*pNewOverlayObject);
                            maOverlayGroup.append(std::move(pNewOverlayObject));
                        }
                        insertNewlyCreatedOverlayObjectForSdrHdl(
                            std::move(pNewOverlayObject),
                            rPageWindow.GetObjectContact(),
                            *xManager.get());
                    }
                }
            }
@@ -1070,6 +1072,39 @@
    return ImpGetBitmapEx(BitmapMarkerKind::Glue_Deselected, BitmapColorIndex::LightGreen);
}

void SdrHdl::insertNewlyCreatedOverlayObjectForSdrHdl(
    std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject,
    const sdr::contact::ObjectContact& rObjectContact,
    sdr::overlay::OverlayManager& rOverlayManager)
{
    // check if we have an OverlayObject
    if(!pOverlayObject)
    {
        return;
    }

    // Add GridOffset for non-linear ViewToDevice transformation (calc)
    if(nullptr != GetObj() && rObjectContact.supportsGridOffsets())
    {
        basegfx::B2DVector aOffset(0.0, 0.0);
        const sdr::contact::ViewObjectContact& rVOC(GetObj()->GetViewContact().GetViewObjectContact(
            const_cast<sdr::contact::ObjectContact&>(rObjectContact)));

        rObjectContact.calculateGridOffsetForViewOjectContact(aOffset, rVOC);

        if(!aOffset.equalZero())
        {
            pOverlayObject->setOffset(aOffset);
        }
    }

    // add to OverlayManager
    rOverlayManager.add(*pOverlayObject);

    // add to local OverlayObjectList - ownership change (!)
    maOverlayGroup.append(std::move(pOverlayObject));
}

SdrHdlColor::SdrHdlColor(const Point& rRef, Color aCol, const Size& rSize, bool bLum)
:   SdrHdl(rRef, SdrHdlKind::Color),
    aMarkerSize(rSize),
@@ -1121,8 +1156,10 @@
                                ));

                            // OVERLAYMANAGER
                            xManager->add(*pNewOverlayObject);
                            maOverlayGroup.append(std::move(pNewOverlayObject));
                            insertNewlyCreatedOverlayObjectForSdrHdl(
                                std::move(pNewOverlayObject),
                                rPageWindow.GetObjectContact(),
                                *xManager.get());
                        }
                    }
                }
@@ -1280,8 +1317,12 @@
                                ));

                            pNewOverlayObject->setBaseColor(IsGradient() ? COL_BLACK : COL_BLUE);
                            xManager->add(*pNewOverlayObject);
                            maOverlayGroup.append(std::move(pNewOverlayObject));

                            // OVERLAYMANAGER
                            insertNewlyCreatedOverlayObjectForSdrHdl(
                                std::move(pNewOverlayObject),
                                rPageWindow.GetObjectContact(),
                                *xManager.get());

                            // arrowhead
                            Point aLeft(aMidPoint.X() + static_cast<sal_Int32>(aPerpend.getX() * fHalfArrowWidth),
@@ -1301,8 +1342,11 @@
                                    IsGradient() ? COL_BLACK : COL_BLUE
                                ));

                            xManager->add(*pNewOverlayObject);
                            maOverlayGroup.append(std::move(pNewOverlayObject));
                            // OVERLAYMANAGER
                            insertNewlyCreatedOverlayObjectForSdrHdl(
                                std::move(pNewOverlayObject),
                                rPageWindow.GetObjectContact(),
                                *xManager.get());
                        }
                    }
                }
@@ -1425,12 +1469,14 @@
                                    aPosition2
                                ));

                            // OVERLAYMANAGER
                            // color(?)
                            pNewOverlayObject->setBaseColor(COL_LIGHTRED);

                            xManager->add(*pNewOverlayObject);
                            maOverlayGroup.append(std::move(pNewOverlayObject));
                            // OVERLAYMANAGER
                            insertNewlyCreatedOverlayObjectForSdrHdl(
                                std::move(pNewOverlayObject),
                                rPageWindow.GetObjectContact(),
                                *xManager.get());
                        }
                    }
                }
@@ -1482,15 +1528,18 @@
                                        aPosition1,
                                        aPosition2
                                    ));
                                // OVERLAYMANAGER

                                // line part is not hittable
                                pNewOverlayObject->setHittable(false);

                                // color(?)
                                pNewOverlayObject->setBaseColor(COL_LIGHTBLUE);

                                xManager->add(*pNewOverlayObject);
                                maOverlayGroup.append(std::move(pNewOverlayObject));
                                // OVERLAYMANAGER
                                insertNewlyCreatedOverlayObjectForSdrHdl(
                                    std::move(pNewOverlayObject),
                                    rPageWindow.GetObjectContact(),
                                    *xManager.get());
                            }
                        }
                    }
@@ -1532,11 +1581,13 @@
                                sdr::overlay::OverlayPolyPolygonStripedAndFilled(
                                    aWireframePoly));

                            // OVERLAYMANAGER
                            pNewOverlayObject->setBaseColor(COL_BLACK);

                            xManager->add(*pNewOverlayObject);
                            maOverlayGroup.append(std::move(pNewOverlayObject));
                            // OVERLAYMANAGER
                            insertNewlyCreatedOverlayObjectForSdrHdl(
                                std::move(pNewOverlayObject),
                                rPageWindow.GetObjectContact(),
                                *xManager.get());
                        }
                    }
                }
@@ -1597,11 +1648,10 @@
                                    eKindOfMarker));

                                // OVERLAYMANAGER
                                if (pNewOverlayObject)
                                {
                                    xManager->add(*pNewOverlayObject);
                                    maOverlayGroup.append(std::move(pNewOverlayObject));
                                }
                                insertNewlyCreatedOverlayObjectForSdrHdl(
                                    std::move(pNewOverlayObject),
                                    rPageWindow.GetObjectContact(),
                                    *xManager.get());
                            }
                        }
                    }
@@ -1713,11 +1763,10 @@
                                eKindOfMarker));

                            // OVERLAYMANAGER
                            if (pNewOverlayObject)
                            {
                                xManager->add(*pNewOverlayObject);
                                maOverlayGroup.append(std::move(pNewOverlayObject));
                            }
                            insertNewlyCreatedOverlayObjectForSdrHdl(
                                std::move(pNewOverlayObject),
                                rPageWindow.GetObjectContact(),
                                *xManager.get());
                        }
                    }
                }
@@ -1784,10 +1833,13 @@
                                nRotationAngle * -F_PI18000,
                                true)); // allow animation; the Handle is not shown at text edit time

                            // OVERLAYMANAGER
                            pNewOverlayObject->setHittable(false);
                            xManager->add(*pNewOverlayObject);
                            maOverlayGroup.append(std::move(pNewOverlayObject));

                            // OVERLAYMANAGER
                            insertNewlyCreatedOverlayObjectForSdrHdl(
                                std::move(pNewOverlayObject),
                                rPageWindow.GetObjectContact(),
                                *xManager.get());
                        }
                    }
                }
@@ -2395,8 +2447,10 @@
                    }

                    // OVERLAYMANAGER
                    xManager->add(*pOverlayObject);
                    maOverlayGroup.append(std::move(pOverlayObject));
                    insertNewlyCreatedOverlayObjectForSdrHdl(
                        std::move(pOverlayObject),
                        rPageWindow.GetObjectContact(),
                        *xManager.get());
                }
            }
        }
@@ -2608,8 +2662,11 @@
                // only informative object, no hit
                pNew->setHittable(false);

                xManager->add(*pNew);
                maOverlayGroup.append(std::move(pNew));
                // OVERLAYMANAGER
                insertNewlyCreatedOverlayObjectForSdrHdl(
                    std::move(pNew),
                    rPageWindow.GetObjectContact(),
                    *xManager.get());
            }
        }
    }
diff --git a/svx/source/svdraw/svdmrkv.cxx b/svx/source/svdraw/svdmrkv.cxx
index bbad824..8a55f973 100644
--- a/svx/source/svdraw/svdmrkv.cxx
+++ b/svx/source/svdraw/svdmrkv.cxx
@@ -43,6 +43,7 @@
#include <svx/svdovirt.hxx>
#include <sdr/overlay/overlayrollingrectangle.hxx>
#include <svx/sdr/overlay/overlaymanager.hxx>
#include <svx/sdr/contact/viewcontact.hxx>
#include <svx/sdrpaintwindow.hxx>
#include <svx/sdrpagewindow.hxx>
#include <svx/sdrhittesthelper.hxx>
@@ -675,11 +676,6 @@
        }
    }

    // apply calc offset to marked object rect
    // ( necessary for handles to be displayed in
    // correct position )
    Point aGridOff = GetGridOffset();

    // There can be multiple mark views, but we're only interested in the one that has a window associated.
    const bool bTiledRendering = comphelper::LibreOfficeKit::isActive() && GetFirstOutputDevice() && GetFirstOutputDevice()->GetOutDevType() == OUTDEV_WINDOW;

@@ -804,20 +800,13 @@
    if (bFrmHdl)
    {
        if(!aRect.IsEmpty())
        { // otherwise nothing is found
        {
            // otherwise nothing is found
            const size_t nSiz0(maHdlList.GetHdlCount());

            if( bSingleTextObjMark )
            {
                const size_t nSiz0=maHdlList.GetHdlCount();
                mpMarkedObj->AddToHdlList(maHdlList);
                const size_t nSiz1=maHdlList.GetHdlCount();
                for (size_t i=nSiz0; i<nSiz1; ++i)
                {
                    SdrHdl* pHdl=maHdlList.GetHdl(i);
                    pHdl->SetObj(mpMarkedObj);
                    pHdl->SetPos( pHdl->GetPos() + aGridOff );
                    pHdl->SetPageView(mpMarkedPV);
                    pHdl->SetObjHdlNum(sal_uInt16(i-nSiz0));
                }
            }
            else
            {
@@ -876,6 +865,20 @@
                    }
                }
            }

            const size_t nSiz1(maHdlList.GetHdlCount());

            // moved setting the missing parameters at SdrHdl here from the
            // single loop above (bSingleTextObjMark), this was missing all
            // the time. Setting SdrObject is now required to correctly get
            // the View-Dependent evtl. GridOffset adapted
            for (size_t i=nSiz0; i<nSiz1; ++i)
            {
                SdrHdl* pHdl=maHdlList.GetHdl(i);
                pHdl->SetObj(mpMarkedObj);
                pHdl->SetPageView(mpMarkedPV);
                pHdl->SetObjHdlNum(sal_uInt16(i-nSiz0));
            }
        }
    }
    else
@@ -888,7 +891,19 @@
            // Default addCropHandles from SdrObject does nothing. When pMarkedObj is SdrGrafObj, previous
            // behaviour occurs (code in svx/source/svdraw/svdograf.cxx). When pMarkedObj is SwVirtFlyDrawObj
            // writer takes the responsibility of adding handles (code in sw/source/core/draw/dflyobj.cxx)
            const size_t nSiz0(maHdlList.GetHdlCount());
            mpMarkedObj->addCropHandles(maHdlList);
            const size_t nSiz1(maHdlList.GetHdlCount());

            // Was missing: Set infos at SdrCropHdl
            for (size_t i=nSiz0; i<nSiz1; ++i)
            {
                SdrHdl* pHdl=maHdlList.GetHdl(i);
                pHdl->SetObj(mpMarkedObj);
                pHdl->SetPageView(mpMarkedPV);
                pHdl->SetObjHdlNum(sal_uInt16(i-nSiz0));
            }

            bDone = true;
        }

@@ -907,7 +922,6 @@
                for (size_t i=nSiz0; i<nSiz1; ++i)
                {
                    SdrHdl* pHdl=maHdlList.GetHdl(i);
                    pHdl->SetPos( pHdl->GetPos() + aGridOff );
                    pHdl->SetObj(pObj);
                    pHdl->SetPageView(pPV);
                    pHdl->SetObjHdlNum(sal_uInt16(i-nSiz0));
@@ -1695,6 +1709,83 @@
    }
}

bool SdrMarkView::getPossibleGridOffsetForSdrObject(
    basegfx::B2DVector& rOffset,
    const SdrObject* pObj,
    const SdrPageView* pPV) const
{
    if(nullptr == pObj || nullptr == pPV)
    {
        return false;
    }

    const OutputDevice* pOutputDevice(GetFirstOutputDevice());

    if(nullptr == pOutputDevice)
    {
        return false;
    }

    const SdrPageWindow* pSdrPageWindow(pPV->FindPageWindow(*pOutputDevice));

    if(nullptr == pSdrPageWindow)
    {
        return false;
    }

    const sdr::contact::ObjectContact& rObjectContact(pSdrPageWindow->GetObjectContact());

    if(!rObjectContact.supportsGridOffsets())
    {
        return false;
    }

    basegfx::B2DVector aOffset(0.0, 0.0);
    const sdr::contact::ViewObjectContact& rVOC(pObj->GetViewContact().GetViewObjectContact(
        const_cast<sdr::contact::ObjectContact&>(rObjectContact)));

    rObjectContact.calculateGridOffsetForViewOjectContact(rOffset, rVOC);

    return !rOffset.equalZero();
}

bool SdrMarkView::getPossibleGridOffsetForPosition(
    basegfx::B2DVector& rOffset,
    const basegfx::B2DPoint& rPoint,
    const SdrPageView* pPV) const
{
    if(nullptr == pPV)
    {
        return false;
    }

    const OutputDevice* pOutputDevice(GetFirstOutputDevice());

    if(nullptr == pOutputDevice)
    {
        return false;
    }

    const SdrPageWindow* pSdrPageWindow(pPV->FindPageWindow(*pOutputDevice));

    if(nullptr == pSdrPageWindow)
    {
        return false;
    }

    const sdr::contact::ObjectContact& rObjectContact(pSdrPageWindow->GetObjectContact());

    if(!rObjectContact.supportsGridOffsets())
    {
        return false;
    }

    basegfx::B2DVector aOffset(0.0, 0.0);
    rObjectContact.calculateGridOffsetForB2DRange(rOffset, basegfx::B2DRange(rPoint));

    return !rOffset.equalZero();
}

SdrObject* SdrMarkView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObject* pObj, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay) const
{
    if(((nOptions & SdrSearchOptions::IMPISMASTER) && pObj->IsNotVisibleAsMaster()) || (!pObj->IsVisible()))
@@ -1708,8 +1799,16 @@
    const bool bTXT(dynamic_cast<const SdrTextObj*>( pObj) != nullptr && static_cast<SdrTextObj*>(pObj)->IsTextFrame());
    SdrObject* pRet=nullptr;
    tools::Rectangle aRect(pObj->GetCurrentBoundRect());
    // hack for calc grid sync
    aRect += pObj->GetGridOffset();

    // add possible GridOffset to up-to-now view-independent BountRect data
    basegfx::B2DVector aGridOffset(0.0, 0.0);
    if(getPossibleGridOffsetForSdrObject(aGridOffset, pObj, pPV))
    {
        aRect += Point(
            basegfx::fround(aGridOffset.getX()),
            basegfx::fround(aGridOffset.getY()));
    }

    sal_uInt16 nTol2(nTol);

    // double tolerance for OLE, text frames and objects in
@@ -2009,6 +2108,7 @@
    SetMarkHandles(pOtherShell);
}

// BoundRect in model coordinates, no GridOffset added
tools::Rectangle SdrMarkView::GetMarkedObjBoundRect() const
{
    tools::Rectangle aRect;
@@ -2016,49 +2116,28 @@
        SdrMark* pM=GetSdrMarkByIndex(nm);
        SdrObject* pO=pM->GetMarkedSdrObj();
        tools::Rectangle aR1(pO->GetCurrentBoundRect());
        // Ensure marked area includes the calc offset
        // ( if applicable ) to sync to grid
        aR1 += pO->GetGridOffset();
        if (aRect.IsEmpty()) aRect=aR1;
        else aRect.Union(aR1);
    }
    return aRect;
}

Point SdrMarkView::GetGridOffset() const
{
    Point aOffset;
    // calculate the area occupied by the union of each marked object
    // ( synced to grid ) and compare to the same unsynced area to calculate
    // the offset. Hopefully that's the sensible thing to do
    const tools::Rectangle& aGroupSyncedRect = GetMarkedObjRect();
    aOffset =   aGroupSyncedRect.TopLeft() - maMarkedObjRectNoOffset.TopLeft();
    return aOffset;
}

// ObjRect in model coordinates, no GridOffset added
const tools::Rectangle& SdrMarkView::GetMarkedObjRect() const
{
    if (mbMarkedObjRectDirty) {
        const_cast<SdrMarkView*>(this)->mbMarkedObjRectDirty=false;
        tools::Rectangle aRect;
        tools::Rectangle aRect2;
        for (size_t nm=0; nm<GetMarkedObjectCount(); ++nm) {
            SdrMark* pM=GetSdrMarkByIndex(nm);
            SdrObject* pO = pM->GetMarkedSdrObj();
            if (!pO)
                continue;
            tools::Rectangle aR1(pO->GetSnapRect());
            // apply calc offset to marked object rect
            // ( necessary for handles to be displayed in
            // correct position )
            if (aRect2.IsEmpty()) aRect2=aR1;
            else aRect2.Union( aR1 );
            aR1 += pO->GetGridOffset();
            if (aRect.IsEmpty()) aRect=aR1;
            else aRect.Union(aR1);
        }
        const_cast<SdrMarkView*>(this)->maMarkedObjRect=aRect;
        const_cast<SdrMarkView*>(this)->maMarkedObjRectNoOffset=aRect2;
    }
    return maMarkedObjRect;
}
diff --git a/svx/source/svdraw/svdobj.cxx b/svx/source/svdraw/svdobj.cxx
index cb104cb..7706cfe 100644
--- a/svx/source/svdraw/svdobj.cxx
+++ b/svx/source/svdraw/svdobj.cxx
@@ -890,6 +890,8 @@
    // central new method which will calculate the BoundRect using primitive geometry
    if(aOutRect.IsEmpty())
    {
        // Use view-independent data - we do not want any connections
        // to e.g. GridOffset in SdrObject-level
        const drawinglayer::primitive2d::Primitive2DContainer xPrimitives(GetViewContact().getViewIndependentPrimitive2DContainer());

        if(!xPrimitives.empty())
@@ -905,7 +907,6 @@
                    static_cast<long>(floor(aRange.getMinY())),
                    static_cast<long>(ceil(aRange.getMaxX())),
                    static_cast<long>(ceil(aRange.getMaxY())));
                aOutRect -= GetGridOffset(); // don't include grid offset
                return;
            }
        }
@@ -1022,8 +1023,6 @@
    pGrabBagItem.reset();
    if (rObj.pGrabBagItem!=nullptr)
        pGrabBagItem.reset(static_cast< SfxGrabBagItem* >( rObj.pGrabBagItem->Clone() ));

    aGridOffset = rObj.aGridOffset;
    return *this;
}

@@ -1706,7 +1705,6 @@
bool SdrObject::Equals(const SdrObject& rOtherObj) const
{
    return (aAnchor.X() == rOtherObj.aAnchor.X() && aAnchor.Y() == rOtherObj.aAnchor.Y() &&
            aGridOffset.X() == rOtherObj.aGridOffset.X() && aGridOffset.Y() == rOtherObj.aGridOffset.Y() &&
            nOrdNum == rOtherObj.nOrdNum && mnNavigationPosition == rOtherObj.mnNavigationPosition &&
            mbSupportTextIndentingOnLineWidthChange == rOtherObj.mbSupportTextIndentingOnLineWidthChange &&
            mbLineIsOutsideGeometry == rOtherObj.mbLineIsOutsideGeometry && bMarkProt == rOtherObj.bMarkProt &&
diff --git a/svx/source/svdraw/svdorect.cxx b/svx/source/svdraw/svdorect.cxx
index d9b74ea..348ef37 100644
--- a/svx/source/svdraw/svdorect.cxx
+++ b/svx/source/svdraw/svdorect.cxx
@@ -316,9 +316,7 @@
    if(IsTextFrame())
    {
        OSL_ENSURE(!IsTextEditActive(), "Do not use a ImpTextframeHdl for highlighting text in active text edit, this will collide with EditEngine paints (!)");
        // hack for calc grid sync to ensure the hatched area
        // for a textbox is displayed at correct position
        std::unique_ptr<SdrHdl> pH(new ImpTextframeHdl(maRect + GetGridOffset()));
        std::unique_ptr<SdrHdl> pH(new ImpTextframeHdl(maRect));
        pH->SetObj(const_cast<SdrRectObj*>(this));
        pH->SetRotationAngle(aGeo.nRotationAngle);
        rHdlList.AddHdl(std::move(pH));
diff --git a/svx/source/svdraw/svdpagv.cxx b/svx/source/svdraw/svdpagv.cxx
index ed73fad..c180fe9 100644
--- a/svx/source/svdraw/svdpagv.cxx
+++ b/svx/source/svdraw/svdpagv.cxx
@@ -35,7 +35,7 @@
#include <svx/svdtypes.hxx>
#include <svx/svdoole2.hxx>

#include <sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdr/contact/objectcontactofpageview.hxx>
#include <svx/sdr/contact/viewobjectcontactredirector.hxx>
#include <svx/fmview.hxx>

diff --git a/svx/source/svdraw/svdview.cxx b/svx/source/svdraw/svdview.cxx
index c68bbe4..0cee85f 100644
--- a/svx/source/svdraw/svdview.cxx
+++ b/svx/source/svdraw/svdview.cxx
@@ -51,6 +51,7 @@
#include <svx/sdr/contact/viewcontact.hxx>
#include <drawinglayer/processor2d/contourextractor2d.hxx>
#include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
#include <svx/sdr/contact/objectcontactofpageview.hxx>
#include <sal/log.hxx>


@@ -1470,5 +1471,12 @@
    }
}

// Default ObjectContact is ObjectContactOfPageView
sdr::contact::ObjectContact* SdrView::createViewSpecificObjectContact(
    SdrPageWindow& rPageWindow,
    const sal_Char* pDebugName) const
{
    return new sdr::contact::ObjectContactOfPageView(rPageWindow, pDebugName);
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/table/tablehandles.cxx b/svx/source/table/tablehandles.cxx
index accbad2..650180b 100644
--- a/svx/source/table/tablehandles.cxx
+++ b/svx/source/table/tablehandles.cxx
@@ -172,8 +172,12 @@
                            {
                                // create overlay object for visible parts
                                std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject(new OverlayTableEdge(aVisible, true));
                                xManager->add(*pOverlayObject);
                                maOverlayGroup.append(std::move(pOverlayObject));

                                // OVERLAYMANAGER
                                insertNewlyCreatedOverlayObjectForSdrHdl(
                                    std::move(pOverlayObject),
                                    rPageWindow.GetObjectContact(),
                                    *xManager.get());
                            }

                            if(aInvisible.count())
@@ -182,8 +186,12 @@
                                // a standard HitTest using the primitives from that overlay object
                                // (see OverlayTableEdge implementation)
                                std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject(new OverlayTableEdge(aInvisible, false));
                                xManager->add(*pOverlayObject);
                                maOverlayGroup.append(std::move(pOverlayObject));

                                // OVERLAYMANAGER
                                insertNewlyCreatedOverlayObjectForSdrHdl(
                                    std::move(pOverlayObject),
                                    rPageWindow.GetObjectContact(),
                                    *xManager.get());
                            }
                        }
                    }
@@ -289,8 +297,12 @@
                        new sdr::overlay::OverlayRectangle(aRange.getMinimum(), aRange.getMaximum(),
                                                           aHilightColor, fTransparence,
                                                           fWidth, 0.0, 0.0, bAnimate));
                    xManager->add(*pOverlayObject);
                    maOverlayGroup.append(std::move(pOverlayObject));

                    // OVERLAYMANAGER
                    insertNewlyCreatedOverlayObjectForSdrHdl(
                        std::move(pOverlayObject),
                        rPageWindow.GetObjectContact(),
                        *xManager.get());
                }
            }
        }